website.git

commit f56d7e9a81db4fb99144b2aa64e1374794856bf7

Author: Adam <git@apiote.xyz>

initial

 argon.go | 111 ++++++++
 go.mod | 9 
 go.sum | 397 +++++++++++++++++++++++++++++
 main.go | 29 ++
 programs/amuse.adoc | 82 ++++++
 programs/asgard.adoc | 78 +++++
 programs/bagend.adoc | 50 +++
 programs/go-dirty.adoc | 1 
 programs/gonk.adoc | 49 +++
 programs/gott.adoc | 85 ++++++
 programs/gott_v2.adoc | 93 ++++++
 programs/index.dirty | 90 ++++++
 router.go | 399 ++++++++++++++++++++++++++++++
 static/favicon/browserconfig.xml | 9 
 static/favicon/safari-pinned-tab.svg | 22 +
 static/favicon/site.webmanifest | 18 +
 static/me.asc | 13 
 static/style.css | 196 ++++++++++++++
 templates/403.html | 12 
 templates/404.html | 13 
 templates/501.html | 14 +
 templates/aside.html | 20 +
 templates/head.html | 18 +
 templates/head_program.html | 19 +
 templates/header.html | 5 
 templates/index.html | 23 +
 templates/nav.html | 10 
 templates/pgp.html | 14 +
 templates/program.html | 18 +
 templates/programs.html | 19 +
 templates/s.html | 21 +
 templates/s201.html | 13 
 templates/short.html | 15 +


diff --git a/argon.go b/argon.go
new file mode 100644
index 0000000000000000000000000000000000000000..90021a3d19acd357530a82fa78e7afdc0ec31b38
--- /dev/null
+++ b/argon.go
@@ -0,0 +1,111 @@
+// MIT (c) alexedwards [https://gist.github.com/alexedwards/34277fae0f48abe36822b375f0f6a621]
+// move to https://github.com/alexedwards/argon2id instead of vendoring
+
+package main
+
+import (
+	"crypto/rand"
+	"crypto/subtle"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"strings"
+
+	"golang.org/x/crypto/argon2"
+)
+
+var (
+	ErrInvalidHash         = errors.New("the encoded hash is not in the correct format")
+	ErrIncompatibleVersion = errors.New("incompatible version of argon2")
+)
+
+type params struct {
+	memory      uint32
+	iterations  uint32
+	parallelism uint8
+	saltLength  uint32
+	keyLength   uint32
+}
+
+func GenerateFromPassword(password string) (encodedHash string, err error) {
+	p := &params{
+		memory:      64 * 1024,
+		iterations:  3,
+		parallelism: 2,
+		saltLength:  16,
+		keyLength:   32,
+	}
+	salt, err := generateRandomBytes(p.saltLength)
+	if err != nil {
+		return "", err
+	}
+
+	hash := argon2.IDKey([]byte(password), salt, p.iterations, p.memory, p.parallelism, p.keyLength)
+
+	b64Salt := base64.RawStdEncoding.EncodeToString(salt)
+	b64Hash := base64.RawStdEncoding.EncodeToString(hash)
+
+	encodedHash = fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, p.memory, p.iterations, p.parallelism, b64Salt, b64Hash)
+
+	return encodedHash, nil
+}
+
+func generateRandomBytes(n uint32) ([]byte, error) {
+	b := make([]byte, n)
+	_, err := rand.Read(b)
+	if err != nil {
+		return nil, err
+	}
+
+	return b, nil
+}
+
+func ComparePasswordAndHash(password, encodedHash string) (match bool, err error) {
+	p, salt, hash, err := decodeHash(encodedHash)
+	if err != nil {
+		return false, err
+	}
+
+	otherHash := argon2.IDKey([]byte(password), salt, p.iterations, p.memory, p.parallelism, p.keyLength)
+
+	if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
+		return true, nil
+	}
+	return false, nil
+}
+
+func decodeHash(encodedHash string) (p *params, salt, hash []byte, err error) {
+	vals := strings.Split(encodedHash, "$")
+	if len(vals) != 6 {
+		return nil, nil, nil, ErrInvalidHash
+	}
+
+	var version int
+	_, err = fmt.Sscanf(vals[2], "v=%d", &version)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+	if version != argon2.Version {
+		return nil, nil, nil, ErrIncompatibleVersion
+	}
+
+	p = &params{}
+	_, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.memory, &p.iterations, &p.parallelism)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	salt, err = base64.RawStdEncoding.DecodeString(vals[4])
+	if err != nil {
+		return nil, nil, nil, err
+	}
+	p.saltLength = uint32(len(salt))
+
+	hash, err = base64.RawStdEncoding.DecodeString(vals[5])
+	if err != nil {
+		return nil, nil, nil, err
+	}
+	p.keyLength = uint32(len(hash))
+
+	return p, salt, hash, nil
+}




diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f8fa0a34ce07c8eebe2486d32cde0438f0abf347
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,9 @@
+module notabug.org/apiote/website
+
+go 1.15
+
+require (
+	apiote.xyz/p/go-dirty v0.0.0-20211218161334-e486e7b5cf43
+	github.com/bytesparadise/libasciidoc v0.6.0
+	golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
+)




diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..9e0c6ddef295256d510e581b273252e655de242f
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,397 @@
+apiote.xyz/p/go-dirty v0.0.0-20211218161334-e486e7b5cf43 h1:C6YDhXc8Wo1ZrhxeJB5BzoYRI3plju2tg0ShTvdEaTQ=
+apiote.xyz/p/go-dirty v0.0.0-20211218161334-e486e7b5cf43/go.mod h1:8QnoYcdnf+1AmRhC7GBUKuCl/wRpfI3Bd58JqDbJNtw=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+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/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
+github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
+github.com/alecthomas/chroma v0.7.1 h1:G1i02OhUbRi2nJxcNkwJaY/J1gHXj9tt72qN6ZouLFQ=
+github.com/alecthomas/chroma v0.7.1/go.mod h1:gHw09mkX1Qp80JlYbmN9L3+4R5o6DJJ3GRShh+AICNc=
+github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
+github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
+github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
+github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
+github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/bytesparadise/libasciidoc v0.6.0 h1:VPYw0epZXIBpNloE9mT9bsTLa6Km/K6ZYXGpwhSjerk=
+github.com/bytesparadise/libasciidoc v0.6.0/go.mod h1:ifAy8QVs1/TRhsqtx/ORiNrHk0NowHih9P5rP9nZI7U=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
+github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
+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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
+github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+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.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.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+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/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.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+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=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/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-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+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=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+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/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.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+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/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/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+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/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+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/mna/pigeon v1.0.1-0.20200224192238-18953b277063 h1:V7s6vhIrNeOqocziAmRoVJh6gnPPx83ovlpT7Hf5shI=
+github.com/mna/pigeon v1.0.1-0.20200224192238-18953b277063/go.mod h1:rkFeDZ0gc+YbnrXPw0q2RlI0QRuKBBPu67fgYIyGRNg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 h1:8Q0qkMVC/MmWkpIdlvZgcv2o2jrlF6zqVOh7W5YHdMA=
+github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
+github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+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=
+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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+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/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sozorogami/gover v0.0.0-20171022184752-b58185e213c5 h1:TAPeDBsd52dRWoWzf5trgBzxzMYHTYjYI+4xNyCdoCU=
+github.com/sozorogami/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:nHNlDYIQZn44RvqH0kCpl/dMMVWXkav0QIgzGxV1Ab4=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/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 v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+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/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+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-20181201002055-351d144fa1fc/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-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=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20200625203802-6e8e738ad208/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-20181107165924-66b7b1311ac8/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-20181128092732-4ed8d59d0b35/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-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=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20190114222345-bf090417da8b/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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190830223141-573d9926052a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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-20201013201025-64a9e34f3752 h1:2ntEwh02rqo2jSsrYmp4yKHHjh0CbXP3ZtSUetSB+q8=
+golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
+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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+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.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+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.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/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.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=




diff --git a/main.go b/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..1fa6ba809d7a51ba9e82bcb8ef0b7ec39a2be7cf
--- /dev/null
+++ b/main.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"math/rand"
+	"time"
+)
+
+func main() {
+	rand.Seed(time.Now().UnixNano())
+
+	pass := flag.String("p", "", "password")
+	flag.Parse()
+
+	if *pass != "" {
+		hash, err := GenerateFromPassword(*pass)
+		if err != nil {
+			fmt.Println(err)
+			return
+		}
+		ioutil.WriteFile("password", []byte(hash), 0600)
+		fmt.Println("Password updated")
+		return
+	}
+
+	route()
+}




diff --git a/programs/amuse.adoc b/programs/amuse.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..7507f29ca5e1d9ef3702b96631400949e89af8fa
--- /dev/null
+++ b/programs/amuse.adoc
@@ -0,0 +1,82 @@
+= a·muse
+apiote <me@apiote.xyz>
+v0.4.0 (Dish of the Day) 2020-11-25
+:toc:
+
+a·muse is a no-JavaScript frontend for The Movie Database. It is also a system that connects films with books which the former are based on, thanks to using data from Wikidata. Finally, a·muse is also a place to collect ideas which films, books, and series watch or read next, and which of those have already been watched or read.
+
+== Name
+
+The name of the system is ‘a·muse.’ The name of the program, command, any package is ‘amuse.’
+
+Both are pronounced the same–[æˈʔmjuːz].
+
+It’s a play of words—‘amuse’ as a verb, and ‘a muse’ as a goddess.
+
+== Building
+
+To build version 0.4.x, You need:
+
+* `go>=1.11`
+* `resvg`
+* `cwebp`
+* `mk`
+
+Then, all You have to do is run `mk`, and—optionally—`mk install`
+
+== Running
+
+----
+Usage of ./amuse:
+  -a string
+      address to run amuse on
+  -c string
+      configPath (default "/etc/amuse.toml")
+  -d string
+      data directory
+  -m string
+      manage command
+  -p int
+      port to run amuse on
+----
+
+== Configuration
+
+a·muse can be configured with command line arguments or with configuration file. Example configuration file can be found in `example.toml`. The only mandatory field is `TmdbApiKey`
+
+== Contribute
+
+This project uses The Code of Merit, which is available as CODE_OF_CONDUCT file.
+
+The roadmap is available in `CHANGELOG.adoc` file and—although it’s not set in stone—feature requests are highly discouraged. Contributions, however, are welcome as patches; please send them to `amuse@git.apiote.xyz` using `git send-email`. Patches must include a sign-off to certify agreement to https://developercertificate.org/[Developer Certificate of Origin].
+
+If You want to translate a·muse, translate strings in `i18n/default.toml` and send patch, or share the translated file in any other way. The translated file must be named `tag.toml`, where `tag` is the language tag of the translation. Translations don’t have to be full; a·muse falls back to default (en-GB) when strings are missing.
+
+All communication—questions, bugs, etc.—should go through the mailing list available at `amuse@git.apiote.xyz`. Note that all communication will be made public at https://asgard.apiote.xyz/.
+
+This project uses https://nvie.com/posts/a-successful-git-branching-model/[nvie’s branching model].
+
+== Mirrors
+
+The canonical repository for this project is https://git.apiote.xyz/amuse.git it’s mirrored at https://notabug.org/apiote/amuse
+
+Mirrors exist solely for the sake of the code and any additional functions provided by third-party services (including but not limited to issues and pull requests) will not be used and will be ignored.
+
+== Licence
+
+----
+amuse Copyright (C) 2019–2022 apiote
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+----




diff --git a/programs/asgard.adoc b/programs/asgard.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..63048a4e6058fd0399f6ada478c58f1e1c6d6b65
--- /dev/null
+++ b/programs/asgard.adoc
@@ -0,0 +1,78 @@
+= asgard
+apiote <me@apiote.xyz>
+:toc:
+
+asgard is a suite of modules based on email workflow.
+
+hermodr (hermóðr, the messenger) forwards messages from IMAP inbox to another address; it’s designed to be used with https://github.com/emersion/hydroxide[hydroxide].
+
+mimir (Mímir, renowned for his knowledge) is a client-side topic-based mailing list and archive; it acts as a mailing list, forwarding messages based on their In-Reply-To header, and stores them in public archive. Best used as a companion to an open source project.
+
+tyr (Týr, valorous and powerful) is an address-based filter; it lets messages pass through if the pair (sender, recipient) is allowed, directs messages to junk if the pair is explicitly not allowed, and sends a notification to sender if the pair is not known.
+
+vor (Vör, associated with wisdom) is a client-side address-based mailing list. It forwards messages sent to a specific address to all interested parties.
+
+== Building
+
+Because asgard uses generics, go >= 1.18 is needed (currently in beta).
+
+All You have to do is run `go build`.
+
+== Running
+
+----
+asgard serve
+	serves the public archive of mimir, and self-release webpage for tyr
+
+asgard hermodr
+	runs one-time forward of hermodr
+
+asgard mimir
+	runs one-time archiving and forwarding of mimir
+
+asgard tyr
+	runs on time filter of tyr
+asgard tyr list
+	lists currently quarantined messages
+asgard release ID [recipient]
+	releases message from quarantine (and saves rule); if recipient is not given, sender can send messages to any address directed to this inbox
+asgard offend ID
+	moves message to junk and saves sender as known offender
+----
+
+== Configuration
+
+asgard is configured with a configuration file (currently read from current directory). Example file can be found in `config_example.dirty`. All fields are mandatory.
+
+== Contribute
+
+This project uses The Code of Merit, which is available as CODE_OF_CONDUCT file.
+
+The roadmap is available in `CHANGELOG.adoc` file and—although it’s not set in stone—feature requests are highly discouraged. Contributions, however, are welcome as patches; please send them to `asgard@git.apiote.xyz` using `git send-email`. Patches must include a sign-off to certify agreement to https://developercertificate.org/[Developer Certificate of Origin].
+
+All communication—questions, bugs, etc.—should go through the mailing list available at `asgard@git.apiote.xyz`. Note that all communication will be made public at https://asgard.apiote.xyz/.
+
+== Mirrors
+
+The canonical repository for this project is https://git.apiote.xyz/asgard.git it’s mirrored at https://notabug.org/apiote/asgard
+
+Mirrors exist solely for the sake of the code and any additional functions provided by third-party services (including but not limited to issues and pull requests) will not be used and will be ignored.
+
+== Licence
+
+----
+asgard Copyright (C) 2021–2022 apiote
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+----




diff --git a/programs/bagend.adoc b/programs/bagend.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..03ce8b28f8bf68684ab6898c47a9f0b94238225e
--- /dev/null
+++ b/programs/bagend.adoc
@@ -0,0 +1,50 @@
+= bagend
+apiote <me@apiote.xyz>
+v1.0.0 2022-02-10
+:toc:
+
+bagend is a simple library which provides `Assert` and kotlin-like `TODO` functions for Go.
+
+== Usage
+
+`Assert` accepts two arguments: `bool` condition and a `string` message. If the condition is false, `Assert` panics with `string` including the message from second argument and the position in code.
+
+----
+// this will pass
+bagend.Assert(2+2 == 4, "2+2 must equal 4")
+
+// this will panic
+bagend.Assert(2+2 == 5, "2+2 must equal 4")
+----
+
+`TODO` accepts a `string` message and always panics with it and position in code. It also returns an `interface{}` so that it can be used in functions that return.
+
+----
+func convertNumber(number int) int {
+	return bagend.TODO("implement me later").(int)
+}
+----
+
+== Contribute
+
+This project is finished; no more functions will be implemented; all feature requests will be ignored.
+
+This project uses The Code of Merit, which is available as CODE_OF_CONDUCT file.
+
+Fixes and patches are welcome; please send them to `bagend@git.apiote.xyz` using `git send-email`. They must include a sign-off to certify agreement to https://developercertificate.org/[Developer Certificate of Origin].
+
+All communication—questions, bugs, etc.—should go through the mailing list available at `bagend@git.apiote.xyz`. Note that all communication will be made public at https://asgard.apiote.xyz/.
+
+== Mirrors
+
+The canonical repository for this project is https://git.apiote.xyz/bagend.git it’s mirrored at https://notabug.org/apiote/bagend
+
+Mirrors exist solely for the sake of the code and any additional functions provided by third-party services (including but not limited to issues and pull requests) will not be used and will be ignored.
+
+== License
+
+----
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at https://mozilla.org/MPL/2.0/.
+----




diff --git a/programs/go-dirty.adoc b/programs/go-dirty.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..eb79ca6feb42409e4cc0850ed97568ae463dd307
--- /dev/null
+++ b/programs/go-dirty.adoc
@@ -0,0 +1 @@
+Reads dirty and converts to go struct, maps, arrays, slices




diff --git a/programs/gonk.adoc b/programs/gonk.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..ba316314887586105b2d318f4c7801f6222cd1d6
--- /dev/null
+++ b/programs/gonk.adoc
@@ -0,0 +1,49 @@
+= gonk
+apiote <me@apiote.xyz>
+:toc:
+
+terminal reader for honk (https://humungus.tedunangst.com/r/honk)
+
+== setup
+
+create file `account` in `XDG_CONFIG_HOME/gonk` (`$HOME/.config/gonk`) with three lines
+
+```
+username = {username}
+password = {password}
+server = {server}
+```
+
+replace {variables} with what they should be. server should be just host name -- without `http(s)://` in front
+
+== run
+
+run `gonk` to show honks with colours or `gonk -t` to show them without colours.
+
+== license
+
+gonk is adapted from honk examples
+
+```
+Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
+```
+
+GPL applies (see LICENSE)
+
+```
+gonk -- honk reader
+Copyright (C) 2020 apiote
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+```




diff --git a/programs/gott.adoc b/programs/gott.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..b131b6a6c223654bdd49aefbb23cb5307aa57b8d
--- /dev/null
+++ b/programs/gott.adoc
@@ -0,0 +1,85 @@
+= gott
+apiote <me@apiote.xyz>
+v1.1.2 2020-04-24
+:toc:
+
+gott is a Railway Oriented Programming library for Go.
+
+[WARNING]
+Version 1 of gott is deprecated, please use version 2 which uses generics
+
+In ROP a program is a chain of functions wrapped in blocks resembling track switches. It’s a simplification of an Either monad.
+
+gott provides N types of blocks:
+
+* Bind, which wraps a function that continues on the happy track or switches to the sad track
+
+    >------+-------->
+            \
+             \
+    >---------+----->
+
+* Map, which wraps a function that will alwayc continue on the happy track
+
+    >--------------->
+    >--------------->
+
+* Tee, which wraps a function performing side effects and can switch to the sad track
+
+             _
+             |
+    >--------++----->
+               \
+                \
+    >------------+-->
+
+* SafeTee, which is to Tee what Map is to Bind
+
+             _
+             |
+    >--------+------>
+    >--------------->
+
+* Recover, which wraps a function that tries to return to the happy Path
+
+    >--------+------>
+            /
+           /
+    >-----+--------->
+
+* Catch, which switches to the sad track in case of a panic
+* Handle, which does different things depending on which track the processing is
+
+== Usage
+
+Provided functions are methods of `Result` and return `Result` so that they can be chained.
+
+Usage can be seen in tests, the simplest being
+
+    import (
+    	"apiote.xyz/p/gott"
+    )
+    func divide5(by ...interface{}) (interface{}, error) {
+    	if b := by[0].(int); b == 0 {
+    		return Tuple(by), errors.New("divideByZero")
+    	} else {
+    		return 5 / b, nil
+    	}
+    func main() {
+    	s, e := NewResult(5).Bind(divide5).Finish()
+    	// s == 1; e == nil
+    }
+
+== Mirrors
+
+The canonical repository for this project is https://git.apiote.xyz/gott.git it’s mirrored at https://notabug.org/apiote/gott
+
+Mirrors exist solely for the sake of the code and any additional functions provided by third-party services (including but not limited to issues and pull requests) will not be used and will be ignored.
+
+== License
+
+----
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at https://mozilla.org/MPL/2.0/.
+----




diff --git a/programs/gott_v2.adoc b/programs/gott_v2.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..60f5ec8c59bcc03b6f09d2cbc057a65c91e93e68
--- /dev/null
+++ b/programs/gott_v2.adoc
@@ -0,0 +1,93 @@
+= gott
+apiote <me@apiote.xyz>
+v2.0.3 2022-04-12
+:toc:
+
+gott is a Railway Oriented Programming library for Go.
+
+In ROP a program is a chain of functions wrapped in blocks resembling track switches. It’s a simplification of an Either monad.
+
+gott provides N types of blocks:
+
+* Bind, which wraps a function that continues on the happy track or switches to the sad track
+
+    >------+-------->
+            \
+             \
+    >---------+----->
+
+* Map, which wraps a function that will alwayc continue on the happy track
+
+    >--------------->
+    >--------------->
+
+* Tee, which wraps a function performing side effects and can switch to the sad track
+
+             _
+             |
+    >--------++----->
+               \
+                \
+    >------------+-->
+
+* SafeTee, which is to Tee what Map is to Bind
+
+             _
+             |
+    >--------+------>
+    >--------------->
+
+* Recover, which wraps a function that tries to return to the happy Path
+
+    >--------+------>
+            /
+           /
+    >-----+--------->
+
+* Catch, which switches to the sad track in case of a panic
+* Handle, which does different things depending on which track the processing is
+
+== Usage
+
+Provided functions are methods of `R[T any]` generic and return `R[T]` so that they can be chained.
+
+Usage can be seen in tests, the simplest being
+
+    import (
+    	"apiote.xyz/p/gott/v2"
+    )
+    func divide5(by int) (int, error) {
+    	if by == 0 {
+    		return by, errors.New("divideByZero")
+    	} else {
+    		return 5 / by, nil
+    	}
+    }
+    func main() {
+    	r := R[int]{S: 5}.Bind(divide5)
+    	// r.S == 1; r.E == nil
+    }
+
+== Contribute
+
+This project is finished; no more functions will be implemented; all feature requests will be ignored.
+
+This project uses The Code of Merit, which is available as CODE_OF_CONDUCT file.
+
+Fixes and patches are welcome; please send them to `gott@git.apiote.xyz` using `git send-email`. They must include a sign-off to certify agreement to https://developercertificate.org/[Developer Certificate of Origin].
+
+All communication—questions, bugs, etc.—should go through the mailing list available at `gott@git.apiote.xyz`. Note that all communication will be made public at https://asgard.apiote.xyz/.
+
+== Mirrors
+
+The canonical repository for this project is https://git.apiote.xyz/gott.git it’s mirrored at https://notabug.org/apiote/gott
+
+Mirrors exist solely for the sake of the code and any additional functions provided by third-party services (including but not limited to issues and pull requests) will not be used and will be ignored.
+
+== License
+
+----
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at https://mozilla.org/MPL/2.0/.
+----




diff --git a/programs/index.dirty b/programs/index.dirty
new file mode 100644
index 0000000000000000000000000000000000000000..cd9cc2220fca4ea64c54f9340ae2cc6f0ad51394
--- /dev/null
+++ b/programs/index.dirty
@@ -0,0 +1,90 @@
+(
+	(
+		('name' 'a·muse')
+		('tldr' 'a no-JavaScript frontend for The Movie Database')
+		('defaultVersion' '')
+		('source' 'https://git.apiote.xyz/git/amuse.git')
+		('versions'
+			(
+				('' (
+					('description' 'amuse.adoc')
+					('module' 'apiote.xyz/p/amuse')
+				))
+			)
+		)
+	)
+	(
+		('name' 'asgard')
+		('tldr' 'a suite of modules based on email workflow')
+		('defaultVersion' '')
+		('source' 'https://git.apiote.xyz/git/asgard.git')
+		('versions'
+			(
+				('' (
+					('description' 'asgard.adoc')
+					('module' 'apiote.xyz/p/asgard')
+				))
+			)
+		)
+	)
+	(
+		('name' 'bagend')
+		('tldr' 'a simple library which provides `Assert` and kotlin-like `TODO` functions for Go')
+		('defaultVersion' '')
+		('source' 'https://git.apiote.xyz/git/bagend.git')
+		('versions'
+			(
+				('' (
+					('description' 'bagend.adoc')
+					('module' 'apiote.xyz/p/bagend')
+				))
+			)
+		)
+	)
+	(
+		('name' 'go-dirty')
+		('tldr' 'go dirty library')
+		('defaultVersion' '')
+		('source' 'https://git.apiote.xyz/git/go-dirty.git')
+		('versions'
+			(
+				('' (
+					('description' 'go-dirty.adoc')
+					('module' 'apiote.xyz/p/go-dirty')
+				))
+			)
+		)
+	)
+	(
+		('name' 'gonk')
+		('tldr' 'terminal reader for honk')
+		('defaultVersion' '')
+		('source' 'https://git.apiote.xyz/git/gonk.git')
+		('versions'
+			(
+				('' (
+					('description' 'gonk.adoc')
+					('module' 'apiote.xyz/p/gonk')
+				))
+			)
+		)
+	)
+	(
+		('name' 'gott')
+		('tldr' 'Railway Oriented Programming framework for Go')
+		('defaultVersion' 'v2')
+		('source' 'https://git.apiote.xyz/git/gott.git')
+		('versions'
+			(
+				('' (
+					('description' 'gott.adoc')
+					('module' 'apiote.xyz/p/gott')
+				))
+				('v2' (
+					('description' 'gott_v2.adoc')
+					('module' 'apiote.xyz/p/gott/v2')
+				))
+			)
+		)
+	)
+)




diff --git a/router.go b/router.go
new file mode 100644
index 0000000000000000000000000000000000000000..e612c2e049791e79ebdbdaf779faafa6e5e5af7a
--- /dev/null
+++ b/router.go
@@ -0,0 +1,399 @@
+package main
+
+import (
+	"fmt"
+	"html/template"
+	"io"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"mime"
+	"net/http"
+	"os"
+	"strings"
+	"bytes"
+
+	"apiote.xyz/p/go-dirty"
+	"github.com/bytesparadise/libasciidoc"
+	"github.com/bytesparadise/libasciidoc/pkg/configuration"
+)
+
+type Redirection struct {
+	ID  string
+	URL string
+}
+
+type Version struct {
+	Description string
+	Module      string
+	Content     template.HTML
+}
+
+type Program struct {
+	Name           string
+	Tldr           string
+	DefaultVersion string
+	Source         string
+	Versions       map[string]Version
+	Tag            string
+	Module         string
+	Content        template.HTML
+}
+
+func static(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	var file *os.File
+	var err error
+	if len(path) < 2 || len(path) > 3 {
+		renderStatus(w, 404)
+	} else if len(path) == 2 {
+		file, err = os.Open("static/" + path[1])
+		defer file.Close()
+	} else if len(path) == 3 {
+		file, err = os.Open("static/favicon/" + path[2])
+		defer file.Close()
+	}
+	if err != nil && os.IsNotExist(err) {
+		renderStatus(w, 404)
+		return
+	} else if err != nil {
+		log.Println(err)
+		fmt.Fprint(w, "Error 500")
+		return
+	}
+	s := strings.Split(file.Name(), ".")
+	ext := "." + s[len(s)-1]
+	mimetype := mime.TypeByExtension(ext)
+	w.Header().Set("Content-Type", mimetype+"; charset=utf-8")
+	_, err = io.Copy(w, file)
+	if err != nil {
+		log.Println(err)
+		fmt.Fprint(w, "Error 500")
+	}
+}
+
+func showHtml(w http.ResponseWriter, name string, data interface{}) {
+	t, err := template.ParseFiles("templates/"+name+".html", "templates/aside.html", "templates/header.html", "templates/nav.html", "templates/head.html", "templates/head_program.html")
+	if err != nil {
+		log.Println(err)
+		if os.IsNotExist(err) {
+			renderStatus(w, 501)
+			return
+		}
+		fmt.Fprint(w, "Error 500")
+		return
+	}
+	err = t.Execute(w, data)
+	if err != nil {
+		log.Println(err)
+		fmt.Fprint(w, "Error 500")
+		return
+	}
+}
+
+func renderStatus(w http.ResponseWriter, status int) {
+	w.WriteHeader(status)
+	showHtml(w, fmt.Sprint(status), nil)
+}
+
+func index(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	if path[0] == "" {
+		showHtml(w, "index", nil)
+	}
+	if path[0] != "" {
+		renderStatus(w, 404)
+	}
+}
+
+func donate(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	if len(path) == 1 {
+		showHtml(w, "donate", nil)
+	} else if path[1] == "" {
+		w.Header().Add("Location", "/donate")
+		w.WriteHeader(301)
+	} else if path[1] != "" {
+		renderStatus(w, 404)
+	}
+}
+
+func readPrograms() (map[string]Program, error) {
+	m := map[string]Program{}
+	programs := []Program{}
+	file, err := os.Open("programs/index.dirty")
+	if err != nil {
+		log.Println(err)
+		return m, err
+	}
+	defer file.Close()
+	err = dirty.LoadStruct(file, &programs)
+	if err != nil {
+		log.Println(err)
+		log.Println(programs)
+	}
+	for _, program := range programs {
+		m[program.Name] = program
+	}
+	return m, err
+}
+
+func programs(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	programs, err := readPrograms()
+	if err != nil {
+		renderStatus(w, 500)
+		return
+	}
+	var (
+		program Program
+		version Version
+		present bool
+	)
+	if path[1] == "" {
+		showHtml(w, "programs", programs)
+		return
+	} else if len(path) == 2 {
+		name := path[1]
+		program = programs[name]
+		version, present = program.Versions[""]
+	} else if len(path) == 3 {
+		name := path[1]
+		program = programs[name]
+		version, present = program.Versions[path[2]]
+	} else {
+		renderStatus(w, 404)
+	}
+	if !present {
+		renderStatus(w, 404)
+	}
+	file, err := os.Open("programs/" + version.Description)
+	if err != nil {
+		if os.IsNotExist(err) {
+			renderStatus(w, 404)
+		} else {
+			log.Println(err)
+		}
+		return
+	}
+	defer file.Close()
+	content, err := io.ReadAll(file)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+	if len(path) > 2 {
+		program.Tag = path[2]
+	} else {
+		program.Tag = ""
+	}
+	program.Module = version.Module
+
+	reader := strings.NewReader(string(content))
+	writer := bytes.NewBuffer([]byte{})
+	config := configuration.NewConfiguration()
+	libasciidoc.Convert(reader, writer, config)
+	program.Content = template.HTML(writer.Bytes())
+
+	showHtml(w, "program", program)
+}
+
+func blogEntries(w http.ResponseWriter, r *http.Request) {
+}
+
+func pgp(w http.ResponseWriter, r *http.Request) {
+	accept := r.Header["Accept"][0]
+	path := strings.Split(r.URL.Path[1:], "/")
+	if path[1] == "" {
+		renderStatus(w, 404)
+	} else {
+		file, err := os.Open("static/" + path[1] + ".asc")
+		defer file.Close()
+		if err != nil && os.IsNotExist(err) {
+			renderStatus(w, 404)
+			return
+		} else if err != nil {
+			log.Println(err)
+			fmt.Fprint(w, "Error 500")
+			return
+		}
+		key, err := ioutil.ReadAll(file)
+		if err != nil {
+			log.Println(err)
+			fmt.Fprint(w, "Error 500")
+			return
+		}
+		w.Header().Set("Vary", "Accept")
+		if strings.Contains(accept, "text/html") {
+			showHtml(w, "pgp", string(key))
+		} else {
+			w.Header().Set("Content-Type", "application/pgp-keys")
+			fmt.Fprintf(w, "%s", key)
+		}
+	}
+}
+
+func shortRedirect(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	if len(path) == 2 && path[1] == "" {
+		if r.Method == "" || r.Method == "GET" {
+			showHtml(w, "s", nil)
+		} else if r.Method == "POST" {
+			r.ParseForm()
+			id := r.PostForm.Get("id")
+			url := r.PostForm.Get("url")
+			password := r.PostForm.Get("password")
+			if id == "" {
+				var letters = []rune("3478ABCDEFHJKMNRTWXY")
+				b := make([]rune, 6)
+				for i := range b {
+					b[i] = letters[rand.Intn(len(letters))]
+				}
+				id = string(b)
+			} else {
+				id = strings.ToUpper(id)
+			}
+			if url == "" {
+				renderStatus(w, 400)
+				return
+			}
+			hash, err := ioutil.ReadFile("password")
+			if err != nil {
+				log.Println(err)
+				fmt.Fprint(w, "Error 500")
+				return
+			}
+			passMatch, err := ComparePasswordAndHash(password, string(hash))
+			if err != nil {
+				log.Println(err)
+				fmt.Fprint(w, "Error 500")
+				return
+			}
+			if !passMatch {
+				renderStatus(w, 403)
+				return
+			}
+
+			// todo check duplicates
+
+			file, err := os.OpenFile("s.toml", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
+			defer file.Close()
+			if err != nil {
+				log.Println(err)
+				fmt.Fprint(w, "Error 500")
+				return
+			}
+			_, err = file.WriteString(id + " = " + url + "\n")
+			if err != nil {
+				log.Println(err)
+				fmt.Fprint(w, "Error 500")
+				return
+			}
+			w.Header().Add("X-Redirection", "https://apiote.xyz/s/"+id)
+			w.WriteHeader(201)
+			showHtml(w, "s201", Redirection{id, url})
+		}
+	} else if len(path) != 2 {
+		renderStatus(w, 404)
+	} else {
+		id := strings.ToUpper(path[1])
+		data, err := ioutil.ReadFile("s.toml")
+		if err != nil {
+			log.Println(err)
+			fmt.Fprint(w, "Error 500")
+			return
+		}
+		for _, line := range strings.Split(string(data), "\n") {
+			if line == "" {
+				break
+			}
+			redirection := strings.Split(line, "=")
+			redirectionID := strings.Trim(redirection[0], " ")
+			redirectionURL := strings.Trim(redirection[1], " ")
+			if redirectionID == id {
+				http.Redirect(w, r, redirectionURL, http.StatusMovedPermanently)
+				return
+			}
+		}
+		renderStatus(w, 404)
+	}
+}
+
+func shortShow(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	if len(path) == 2 && path[1] != "" {
+		id := strings.ToUpper(path[1])
+		data, err := ioutil.ReadFile("s.toml")
+		if err != nil {
+			log.Println(err)
+			fmt.Fprint(w, "Error 500")
+			return
+		}
+		for _, line := range strings.Split(string(data), "\n") {
+			if line == "" {
+				break
+			}
+			redirection := strings.Split(line, "=")
+			redirectionID := strings.Trim(redirection[0], " ")
+			redirectionURL := strings.Trim(redirection[1], " ")
+			if redirectionID == id {
+				showHtml(w, "short", Redirection{redirectionID, redirectionURL})
+				return
+			}
+		}
+		renderStatus(w, 404)
+	} else {
+		renderStatus(w, 404)
+	}
+}
+
+func wkd(w http.ResponseWriter, r *http.Request) {
+	path := strings.Split(r.URL.Path[1:], "/")
+	if path[3] == "" {
+		renderStatus(w, 404)
+	} else {
+		file, err := os.Open("static/" + path[3] + ".pgp")
+		defer file.Close()
+		if err != nil && os.IsNotExist(err) {
+			renderStatus(w, 404)
+			return
+		} else if err != nil {
+			log.Println(err)
+			fmt.Fprint(w, "Error 500")
+			return
+		}
+		s := strings.Split(file.Name(), ".")
+		ext := "." + s[len(s)-1]
+		mimetype := mime.TypeByExtension(ext)
+		w.Header().Set("Content-Type", mimetype)
+		w.Header().Set("Access-Control-Allow-Origin", "*")
+		_, err = io.Copy(w, file)
+		if err != nil {
+			log.Println(err)
+			fmt.Fprint(w, "Error 500")
+		}
+	}
+}
+
+func route() {
+	http.HandleFunc("/", index)
+	http.HandleFunc("/static/", static)
+
+	http.HandleFunc("/b/", blogEntries)
+	http.HandleFunc("/blog/", blogEntries)
+	http.HandleFunc("/p/", programs)
+	http.HandleFunc("/programs/", programs)
+	http.HandleFunc("/donate", donate)
+	http.HandleFunc("/donate/", donate) // xxx historical reasons for trailing slash
+	http.HandleFunc("/pgp/", pgp)
+
+	http.HandleFunc("/s/", shortRedirect)
+	http.HandleFunc("/short/", shortShow)
+
+	http.HandleFunc("/.well-known/openpgpkey/hu/", wkd)
+
+	e := http.ListenAndServe("127.0.0.1:8080", nil)
+	if e != nil {
+		log.Println(e)
+	}
+}




diff --git a/static/favicon/android-chrome-192x192.png b/static/favicon/android-chrome-192x192.png
new file mode 100644
index 0000000000000000000000000000000000000000..bf41363fd5f5401dac7fc6f3f04af05188f49a63
Binary files /dev/null and b/static/favicon/android-chrome-192x192.png differ




diff --git a/static/favicon/android-chrome-512x512.png b/static/favicon/android-chrome-512x512.png
new file mode 100644
index 0000000000000000000000000000000000000000..29691bf2705fdb3fb101179510c9e85ff0965dd4
Binary files /dev/null and b/static/favicon/android-chrome-512x512.png differ




diff --git a/static/favicon/apple-touch-icon.png b/static/favicon/apple-touch-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb91a67c65c543fc34b7cd1554cf3a1084ad8526
Binary files /dev/null and b/static/favicon/apple-touch-icon.png differ




diff --git a/static/favicon/browserconfig.xml b/static/favicon/browserconfig.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a07997f7e5a5d060ee760aaddf9f1727be4e1219
--- /dev/null
+++ b/static/favicon/browserconfig.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<browserconfig>
+    <msapplication>
+        <tile>
+            <square150x150logo src="/static/favicon/mstile-150x150.png"/>
+            <TileColor>#ffc40d</TileColor>
+        </tile>
+    </msapplication>
+</browserconfig>




diff --git a/static/favicon/favicon-16x16.png b/static/favicon/favicon-16x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..37d49ad6d982c9cbd57049f4871a5deec901a642
Binary files /dev/null and b/static/favicon/favicon-16x16.png differ




diff --git a/static/favicon/favicon-32x32.png b/static/favicon/favicon-32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..7a46e7bc29efd2a668a3f481f807450e0b6fc591
Binary files /dev/null and b/static/favicon/favicon-32x32.png differ




diff --git a/static/favicon/favicon.ico b/static/favicon/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..878605406a1c95c0ad314440efad701524837410
Binary files /dev/null and b/static/favicon/favicon.ico differ




diff --git a/static/favicon/mstile-144x144.png b/static/favicon/mstile-144x144.png
new file mode 100644
index 0000000000000000000000000000000000000000..25c7bb3c67de91c95068be55a4e3bfd58f0479b1
Binary files /dev/null and b/static/favicon/mstile-144x144.png differ




diff --git a/static/favicon/mstile-150x150.png b/static/favicon/mstile-150x150.png
new file mode 100644
index 0000000000000000000000000000000000000000..83a42cedc2d3b94cb8b2e7278272d51e8058e16b
Binary files /dev/null and b/static/favicon/mstile-150x150.png differ




diff --git a/static/favicon/mstile-310x150.png b/static/favicon/mstile-310x150.png
new file mode 100644
index 0000000000000000000000000000000000000000..68cb7e0dffbc3d84d23631fab9b6a5dedc7d3862
Binary files /dev/null and b/static/favicon/mstile-310x150.png differ




diff --git a/static/favicon/mstile-310x310.png b/static/favicon/mstile-310x310.png
new file mode 100644
index 0000000000000000000000000000000000000000..58460790efd78cfc743131cf3cb3b445e4bae280
Binary files /dev/null and b/static/favicon/mstile-310x310.png differ




diff --git a/static/favicon/mstile-70x70.png b/static/favicon/mstile-70x70.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b7d3df853e7ef9f1e6cadb97417472c50c65b54
Binary files /dev/null and b/static/favicon/mstile-70x70.png differ




diff --git a/static/favicon/safari-pinned-tab.svg b/static/favicon/safari-pinned-tab.svg
new file mode 100644
index 0000000000000000000000000000000000000000..8655927a735aba07970a0a6cb34184debabb5e93
--- /dev/null
+++ b/static/favicon/safari-pinned-tab.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
+ width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
+ preserveAspectRatio="xMidYMid meet">
+<metadata>
+Created by potrace 1.14, written by Peter Selinger 2001-2017
+</metadata>
+<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
+fill="#000000" stroke="none">
+<path d="M3295 6990 c-1520 -96 -2792 -1140 -3179 -2610 -126 -478 -144 -1042
+-50 -1535 194 -1011 813 -1873 1719 -2391 391 -224 866 -376 1340 -430 200
+-22 549 -22 750 0 809 91 1528 437 2100 1010 563 564 913 1295 1001 2091 34
+312 18 719 -42 1030 -254 1321 -1244 2383 -2539 2725 -340 90 -757 131 -1100
+110z m545 -655 c950 -112 1771 -688 2198 -1541 346 -691 392 -1497 128 -2224
+-218 -601 -638 -1114 -1184 -1447 -347 -211 -719 -339 -1147 -394 -166 -22
+-541 -16 -715 10 -632 96 -1169 367 -1610 811 -441 445 -712 1001 -796 1635
+-20 157 -23 500 -5 655 73 631 342 1201 775 1648 166 171 283 269 466 391 377
+251 783 401 1230 456 148 18 507 18 660 0z"/>
+</g>
+</svg>




diff --git a/static/favicon/site.webmanifest b/static/favicon/site.webmanifest
new file mode 100644
index 0000000000000000000000000000000000000000..e2625b90232a02ffd2cfdf765841392c18b1bd7e
--- /dev/null
+++ b/static/favicon/site.webmanifest
@@ -0,0 +1,18 @@
+{
+    "name": "apiote",
+    "short_name": "apiote",
+    "icons": [
+        {
+            "src": "/static/favicon/android-chrome-192x192.png",
+            "sizes": "192x192",
+            "type": "image/png"
+        },
+        {
+            "src": "/static/favicon/android-chrome-512x512.png",
+            "sizes": "512x512",
+            "type": "image/png"
+        }
+    ],
+    "theme_color": "#db9d3b",
+    "background_color": "#db9d3b"
+}




diff --git a/static/me.asc b/static/me.asc
new file mode 100644
index 0000000000000000000000000000000000000000..8d96054e779046fe06994ba7e7ab9d62411e146b
--- /dev/null
+++ b/static/me.asc
@@ -0,0 +1,13 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEYPWnzhYJKwYBBAHaRw8BAQdA48qz39KcHTMeqMlrN2w8KkJnsSHbJPUjph6J
+lVAqSVq0FmFwaW90ZSA8bWVAYXBpb3RlLnh5ej6IkAQTFggAOBYhBKxgavEgSylO
+Sr2HUMEeEnLvO4FkBQJg9afOAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJ
+EMEeEnLvO4FknHsA/2kBueBTX6L1W33d93LVUACXAmYJ3TpIkRDBEa4J+4SGAQCV
+igVYLwaFwxokMibDW6Kjn7U+9NrYg5pkmdVnFZQaDbg4BGD1p84SCisGAQQBl1UB
+BQEBB0CPaiL+yvSwxloXFK0eeifRUw/tl7ykcMSO0PPY0ST/UgMBCAeIeAQYFggA
+IBYhBKxgavEgSylOSr2HUMEeEnLvO4FkBQJg9afOAhsMAAoJEMEeEnLvO4Fk7Q8B
+AKev4rZnD0F/upxLIX+Y5BgMZDjuxRld7viqPbh4oPVOAPsG+1ppdVy+yZm5kTHY
+3zQQ1rfj7Qphz4xXotfD8ZcUDw==
+=j3bY
+-----END PGP PUBLIC KEY BLOCK-----




diff --git a/static/s8y7oh5xrdpu9psba3i5ntk64ohouhga.pgp b/static/s8y7oh5xrdpu9psba3i5ntk64ohouhga.pgp
new file mode 100644
index 0000000000000000000000000000000000000000..c2946766a226be2e09cb885ac8e8f5035acb35da
Binary files /dev/null and b/static/s8y7oh5xrdpu9psba3i5ntk64ohouhga.pgp differ




diff --git a/static/style.css b/static/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..df45a015ac0dc3458b608684c41b7b929d33d7a9
--- /dev/null
+++ b/static/style.css
@@ -0,0 +1,196 @@
+:root {
+	--accent: #745016;
+	--accent-hover: #000000;
+	--toa: #ffffff;
+	--text: #292929;
+	--bg: #fafafa;
+	--border: #737373;
+	--link: #005b85;
+	--link-on-dark: #1ab6ff;
+	--visited: #680bea;
+	--terminal-bg: #292929;
+	--terminal-text: #cdb360;
+	--dark-bg: #212121;
+	--text-on-dark: #fafafa;
+	--yellow: #db9d3b;
+	--black: #292929;
+}
+
+@media (prefers-color-scheme: dark) {
+	:root {
+		--accent: #db9d3b;
+		--accent-hover: #ffffff;
+		--toa: #000000;
+		--text: #fafafa;
+		--bg: #292929;
+		--border: #919191;
+		--link: #38c0ff;
+		--link-on-dark: #1ab6ff;
+		--visited: #c7a4f9;
+		--terminal-bg: #292929;
+		--terminal-text: #cdb360;
+		--dark-bg: #212121;
+		--text-on-dark: #fafafa;
+		--yellow: #db9d3b;
+		--black: #292929;
+	}
+}
+
+* {
+	box-sizing: border-box;
+	color: var(--text);
+	background: var(--bg);
+}
+
+a {
+	color: var(--link);
+	text-decoration-color: var(--link);
+}
+
+a:visited {
+	color: var(--visited);
+	text-decoration-color: var(--visited);
+}
+
+a:hover, a:focus, a:visited:focus, a:visited:hover {
+	color: var(--accent);
+	text-decoration-color: var(--accent);
+}
+
+p {
+	max-width: 80ch;
+	font-family: "IBM Plex Serif", serif;
+}
+
+pre {
+	font-family: Iosevka, monospace;
+	background: var(--terminal-bg);
+	color: var(--terminal-text);
+	overflow: scroll;
+	white-space: pre;
+	max-width: 80ch;
+	border: 2px solid var(--border);
+	display: block;
+	padding: 1rem;
+	margin-bottom: 1rem;
+}
+
+code {
+	font-family: Iosevka, monospace;
+	background: var(--terminal-bg);
+	color: var(--terminal-text);
+	overflow: scroll;
+	white-space: pre;
+}
+
+section {
+	margin-bottom: 2rem;
+	width: 85%;
+	background: var(--dark-bg);
+	color: var(--text-on-dark);
+	padding-left: 1rem;
+	padding-right: 1rem;
+	padding-bottom: .5rem;
+}
+
+section > h3 {
+	background: var(--dark-bg);
+	color: var(--link-on-dark);
+	padding: .5rem 0;
+	display: block;
+	border-bottom: 1px solid #e9ecef;
+	display: flex;
+	flex-wrap: wrap;
+}
+
+section > p {
+	margin-top: .5rem;
+	font-size: 1rem;
+	background: var(--dark-bg);
+	color: var(--text-on-dark);
+}
+
+button, input[type=submit] {
+	background: var(--accent);
+	color: var(--toa);
+	border: var(--text) 1px solid;
+	cursor: pointer;
+}
+
+button:hover, button:active, button:focus,
+input[type=submit]:hover, input[type=submit]:active, input[type=submit]:focus {
+	background: var(--accent-hover);
+}
+
+button > a, button > a:hover, button > a:focus, button > a:visited:focus, button > a:visited:hover{
+	background: inherit;
+	color: var(--toa);
+	text-decoration: none;
+}
+
+h1, h2, h3, h4, h5, h6 {
+	font-family: "Fira Sans", sans-serif;
+}
+
+body {
+	margin: 1rem;
+	display: flex;
+	flex-wrap: wrap;
+}
+
+header {
+	font-weight: bold;
+	width: 100%;
+	font-size: 3rem;
+	font-family: "Fira Sans", sans-serif;
+}
+
+nav {
+	width: 100%;
+	margin-bottom: 2rem;
+	font-family: Iosevka, monospace;
+}
+
+nav > ul {
+	margin: .5rem 0;
+	padding: 0;
+	list-style-type: none;
+}
+
+nav > ul > li {
+	display: inline;
+}
+
+main {
+	max-width: 92%;
+	flex-grow: 11;
+	margin: 0 1rem 2rem 1rem;
+}
+
+input {
+	border: var(--border) 1px solid;
+	display: block;
+	margin: .25rem 0 .75rem 0;
+}
+
+label {
+	display: block;
+	font-family: "Fira Sans", sans-serif;
+}
+
+aside {
+	width: 200px;
+	flex-grow: 1;
+}
+
+aside > a {
+	display: block;
+	font-family: Iosevka, monospace;
+	margin-top: .1rem;
+	margin-bottom: 1rem;
+}
+
+.warning * {
+	background: var(--yellow);
+	color: var(--black);
+}




diff --git a/templates/403.html b/templates/403.html
new file mode 100644
index 0000000000000000000000000000000000000000..4011d2fc4349789205c2a130b5aa6e323289073e
--- /dev/null
+++ b/templates/403.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h1>Error 403 – Forbidden</h1>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/404.html b/templates/404.html
new file mode 100644
index 0000000000000000000000000000000000000000..2c5f403f53391b7b5fb897ec13ffc24221c53f5b
--- /dev/null
+++ b/templates/404.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h1>Error 404 — Not Found</h1>
+			<p>‘There was a point to this story, but it has temporarily escaped the chronicler's mind.’</p>
+		</main>
+		{{ template "aside" }}
+	</body>
+</html>




diff --git a/templates/501.html b/templates/501.html
new file mode 100644
index 0000000000000000000000000000000000000000..51177ebfd9078f38e55df555405e68bda3846eb4
--- /dev/null
+++ b/templates/501.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h1>Error 501 — Not Implemented</h1>
+			<p>‘In the beginning the Universe was created.<br/>
+			This has made a lot of people very angry and been widely regarded as a bad move.’</p>
+		</main>
+		{{ template "aside" }}
+	</body>
+</html>




diff --git a/templates/aside.html b/templates/aside.html
new file mode 100644
index 0000000000000000000000000000000000000000..3bba9c6546e957cd4b18cc8113d29c18625cb39f
--- /dev/null
+++ b/templates/aside.html
@@ -0,0 +1,20 @@
+{{- define "aside" -}}
+		<aside>
+			<code>me: undefined
+# ^ that’s a joke</code>
+			<hr/>
+			<label for="git-link">git</label>
+			<a id="git-link" href="https://git.apiote.xyz">git.apiote.xyz</a>
+			<a id="git-link" href="https://notabug.org/apiote">notabug.org/apiote</a>
+			<label for="honk-link">activitypub</label>
+			<a id="honk-link" href="https://honk.apiote.xyz/u/me">@me@honk.apiote.xyz</a>
+			<label for="pixel-link">pixelfed</label>
+			<a id="pixel-link" href="https://pixelfed.uno/@apiote">@apiote@pixelfed.uno</a>
+			<label for="email-link">email</label>
+			<a id="email-link" href="mailto:me@apiote.xyz">me@apiote.xyz</a>
+			<label for="pgp-link">pgp</label>
+			<a id="pgp-link" href="/pgp/me">5A8C74D1318B549B</a>
+
+			<p>The content for this site is <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA</a>. The code for this site is <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPL</a>.</p>
+		</aside>
+{{- end -}}




diff --git a/templates/head.html b/templates/head.html
new file mode 100644
index 0000000000000000000000000000000000000000..366e3db5171b55764e9a7aa95f804f2d5b6eef62
--- /dev/null
+++ b/templates/head.html
@@ -0,0 +1,18 @@
+{{- define "head" -}}
+	<head>
+		<meta charset="utf-8" />
+		<title>Apiote</title>
+		<meta name="viewport" content="width=device-width, initial-scale=1" />
+		<link rel="stylesheet" href="/static/style.css" />
+		<link rel="canonical" href="https://apiote.xyz" />
+		<link rel="apple-touch-icon" sizes="180x180" href="/static/favicon/apple-touch-icon.png">
+		<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon/favicon-32x32.png">
+		<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon/favicon-16x16.png">
+		<link rel="manifest" href="/static/favicon/site.webmanifest">
+		<link rel="mask-icon" href="/static/favicon/safari-pinned-tab.svg" color="#db9d3b">
+		<link rel="shortcut icon" href="/static/favicon/favicon.ico">
+		<meta name="msapplication-TileColor" content="#ffc40d">
+		<meta name="msapplication-config" content="/static/favicon/browserconfig.xml">
+		<meta name="theme-color" content="#db9d3b">
+	</head>
+{{- end -}}




diff --git a/templates/head_program.html b/templates/head_program.html
new file mode 100644
index 0000000000000000000000000000000000000000..7b78507e2956362ef722aebb3b012d26ffd89a08
--- /dev/null
+++ b/templates/head_program.html
@@ -0,0 +1,19 @@
+{{- define "head_program" -}}
+	<head>
+		<meta charset="utf-8" />
+		<title>Apiote</title>
+		<meta name="viewport" content="width=device-width, initial-scale=1" />
+		<link rel="stylesheet" href="/static/style.css" />
+		<link rel="canonical" href="https://apiote.xyz" />
+		<link rel="apple-touch-icon" sizes="180x180" href="/static/favicon/apple-touch-icon.png">
+		<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon/favicon-32x32.png">
+		<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon/favicon-16x16.png">
+		<link rel="manifest" href="/static/favicon/site.webmanifest">
+		<link rel="mask-icon" href="/static/favicon/safari-pinned-tab.svg" color="#db9d3b">
+		<link rel="shortcut icon" href="/static/favicon/favicon.ico">
+		<meta name="msapplication-TileColor" content="#ffc40d">
+		<meta name="msapplication-config" content="/static/favicon/browserconfig.xml">
+		<meta name="theme-color" content="#db9d3b">
+		<meta name="go-import" content="{{.Module}} git {{.Source}}">
+	</head>
+{{- end -}}




diff --git a/templates/header.html b/templates/header.html
new file mode 100644
index 0000000000000000000000000000000000000000..37abc075b09a9b61293406fd709c31b90a30f54f
--- /dev/null
+++ b/templates/header.html
@@ -0,0 +1,5 @@
+{{- define "header" -}}
+		<header>
+			apiote
+		</header>
+{{- end -}}




diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..8a80a453d8677d3b50ba2d7e9e033d2b34fa99a7
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<pre>-----BEGIN GEEK CODE BLOCK-----
+Version: 3.12
+GCS d+ s:-> a- C@$ UL++++$ P--- L+++ !E--- W- N? o? K-? !w--- O? !M-- V?
+PS+++ PE-- Y+ PGP++(+++) !t>+ 5?>+ !X>+ !R !tv b+++ DI++ D? G e*+++ h!>
+r--> y
+------END GEEK CODE BLOCK------</pre>
+			<pre>-----BEGIN GEEK CODE BLOCK-----
+Version: 3.20
+GCS d+ s:-> a- C@$ B+++ L+++ u W- H++++ 7---- !w--- !M-- Z+ F@ PS+++ PE--
+Y+ PGP++(+++) T@ S@ m----(+) J++ !R !tv b+++ DI++ D? e*+++ h!> A++++ r-->
+y
+------END GEEK CODE BLOCK------</pre>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/nav.html b/templates/nav.html
new file mode 100644
index 0000000000000000000000000000000000000000..fc4db29a731527a5e296cb67d9e8386c0aa3e2ab
--- /dev/null
+++ b/templates/nav.html
@@ -0,0 +1,10 @@
+{{- define "nav" -}}
+		<nav>
+			<ul>
+				<li><a href="/">:home</a></li>
+				<!--<li><a href="/kaurselylehu">:kaurselyle’u</a></li>-->
+				<li><a href="/programs/">:programs</a></li>
+				<!--<li><a href="/blog">:blog</a></li>-->
+			</ul>
+		</nav>
+{{- end -}}




diff --git a/templates/pgp.html b/templates/pgp.html
new file mode 100644
index 0000000000000000000000000000000000000000..02bc8d4abeee7e20d49423e13014105216017508
--- /dev/null
+++ b/templates/pgp.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<code><pre>
+{{ . }}
+			</pre></code>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/program.html b/templates/program.html
new file mode 100644
index 0000000000000000000000000000000000000000..404384e84c4138e33037bddfd9e446b47d2718c0
--- /dev/null
+++ b/templates/program.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head_program" . }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h2>{{.Name}}</h2>
+			{{if gt (len .Versions) 1}}<ul>
+				{{range $tag, $_ := .Versions}}<li>{{if $tag}}<a href="/p/{{$.Name}}/{{$tag}}">{{$tag}}</a>{{else}}<a href="/p/{{$.Name}}">v1</a>{{end}}</li>{{end}}
+			</ul>{{end}}
+			<code>{{.Source}}</code>
+
+			<div>{{.Content}}</div>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/programs.html b/templates/programs.html
new file mode 100644
index 0000000000000000000000000000000000000000..2837a78d2ce7bb9914ac38339bc274d52521eb32
--- /dev/null
+++ b/templates/programs.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			{{range .}}
+				<a href="{{.Name}}{{if .DefaultVersion}}/{{.DefaultVersion}}{{end}}" style="text-decoration: none;">
+					<section>
+						<h3>{{.Name}}</h3>
+						<p>{{.Tldr}}</p>
+					</section>
+				</a>
+			{{end}}
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/s.html b/templates/s.html
new file mode 100644
index 0000000000000000000000000000000000000000..863286441c5be4f9653adfb05bba13c71a45379b
--- /dev/null
+++ b/templates/s.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h1>Redirect</h1>
+			<form method="POST" >
+				<label for="url">URL</label>
+				<input type="url" id="url" name="url" required />
+				<label for="password">Password</label>
+				<input type="password" id="password" name="password" required />
+				<label for="id">ID</label>
+				<input id="id" name="id" />
+				<input type="submit" value="create" >
+			</form>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/s201.html b/templates/s201.html
new file mode 100644
index 0000000000000000000000000000000000000000..832c8725e810e14e2e1cde015aa0372f97238012
--- /dev/null
+++ b/templates/s201.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h1>Redirection created</h1>
+			<p>ID (<code>{{ .ID }}</code>) will redirect to <code>{{ .URL }}</code>.</p>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>




diff --git a/templates/short.html b/templates/short.html
new file mode 100644
index 0000000000000000000000000000000000000000..59bc43c7d901696fd97edeb5e82af0d11dfc82a0
--- /dev/null
+++ b/templates/short.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+	{{ template "head" }}
+	<body>
+		{{ template "header" }}
+		{{ template "nav" }}
+		<main>
+			<h1>Redirection</h1>
+			<p>This ID (<code>{{ .ID }}</code>) will redirect to <code>{{ .URL }}</code>.</p>
+
+			<button><a href="{{ .URL }}">Yes, take me there »</a></button>
+		</main>
+		{{ template "aside" . }}
+	</body>
+</html>