initial import

This commit is contained in:
Erik Winter 2020-12-04 12:50:20 +01:00
commit 1df852e7e5
37 changed files with 2045 additions and 0 deletions

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module git.sr.ht/~ewintr/shitty-ssg
go 1.14
require (
git.sr.ht/~ewintr/erikwinternl/shitty-ssg v0.0.0-20201204092507-5528bf33815d // indirect
git.sr.ht/~ewintr/go-kit v0.0.0-20200704112030-36275689b0ea
)

352
go.sum Normal file
View File

@ -0,0 +1,352 @@
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=
git.sr.ht/~ewintr/erikwinternl/shitty-ssg v0.0.0-20201204092507-5528bf33815d/go.mod h1:ka/PzT9A0BNvjcUQpIM0YE1BnOR1/qr6x7XeCUyYDlw=
git.sr.ht/~ewintr/go-kit v0.0.0-20200704112030-36275689b0ea h1:YdHan+/QwjzF05Dlp40BHw5N47nWy2QZCY7aseXf2n0=
git.sr.ht/~ewintr/go-kit v0.0.0-20200704112030-36275689b0ea/go.mod h1:zrpigRr1EHuVGw7GWwvYWwfLgdAwJ110zIRAGtaicvI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
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/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/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.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/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-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
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/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/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
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/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
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-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
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-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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
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-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
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/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
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.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
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/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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-20190125091013-d26f9f9a57f3/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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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/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-20190911185100-cd5d95a43a6e/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-20181122145206-62eef0e2fa9b/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-20180828015842-6cd1fcedba52/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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

51
main.go Normal file
View File

@ -0,0 +1,51 @@
package main
import (
"flag"
"log"
"os"
"path/filepath"
"strings"
"git.sr.ht/~ewintr/shitty-ssg/site"
)
var (
resources = flag.String("resources", "./resources", "folder with templates and other resources")
content = flag.String("content", "./content,/projectx", "comma separated list of folders search for content")
public = flag.String("public", "./public", "target folder for generated site")
)
func main() {
flag.Parse()
if *resources == "" || *content == "" || *public == "" {
log.Fatal("missing parameter")
}
// initialize site
s, err := site.New(*resources)
if err != nil {
log.Fatal(err)
}
// add content
for _, cp := range strings.Split(*content, ",") {
log.Printf("checking %s for content\n", cp)
if err := filepath.Walk(cp, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && filepath.Ext(path) == ".adoc" {
s.AddFilePost(path)
}
return nil
}); err != nil {
log.Fatal(err)
}
}
// render site
if err := s.RenderHTML(*public); err != nil {
log.Fatal(err)
}
}

BIN
resources/about/rss.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

BIN
resources/other/volca.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
{{- template "head" . -}}
<body>
{{- template "menu" -}}
<main>
<article>
<h2 id="hi">Hi,</h2>
<p>As you may have guessed from the contents of this site, I am a Dutch software developer who also likes literature and music and a bunch of other things.</p>
<p>I am old enough to remember what the internet was like before platforms like Facebook, Twitter, Github, etc. came around. Everything was decentralized, everybody had their own website and it actually felt more personal and real than the &ldquo;social&rdquo; media of today.</p>
<p>Since I like to create things, I thought I&rsquo;d make myself an old school personal website again. For my own pleasure. And for others like me. I know you are out there!</p>
<h2 id="rss-feeds">RSS Feeds</h2>
<p>To stay updated, there is an RSS link: <a href="/index.xml"><img src="rss.png" alt="RSS Icon">Recent</a></p>
<h2 id="contact">Contact</h2>
<p>I'm <a href="https://fosstodon.org/@ewintr">@ewintr@fosstodon.org</a> on Mastodon.</p>
<p>Otherwise, you can contact me by sending me an <a href="mailto:info@erikwinter.nl">email</a>.</p>
</article>
</main>
</body>

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
{{- template "head" . -}}
<body>
{{- template "menu" -}}
<main>
<nav class="tagList">
<h2>Tags</h2>
<p>These can refer to both articles and development notes. Well, technically they could refer to short stories too, but I have not yet felt the need to include Docker or Kubernetes in my fiction. It's a safe space, after all.</p>
<ul>
{{- range .Tags -}}
<li><a href="{{ .Link }}">#{{ .Name }}</a></li>
{{- end -}}
</ul>
</nav>
<nav>
<h2>Articles</h2>
<p>Tutorials, essays, thoughts... or just ramblings from someone who thinks too much about computers and minimalism.</p>
<ul>
{{- range .ArticleYears -}}
<li><a href="{{ .Link }}">{{ .Name }}</a></li>
{{- end -}}
</ul>
</nav>
<nav>
<h2>Development Notes</h2>
<p>Programming and other computer related tricks, links and snippets that I'd like to have quick access to. Basically, whenever I Google and all the top links are purple, indicating that I have searched the same thing before, I turn it into a note.</p>
<ul>
{{- range .NoteYears -}}
<li><a href="{{ .Link }}">{{ .Name }}</a></li>
{{- end -}}
</ul>
</nav>
<nav>
<h2>Short Stories &#127475;&#127473;</h2>
<p>Over the course of years, I wrote a lot of short stories in a format that I called <em>Vrij Korte Verhalen</em>, VKV's for short, which could be translated as Rather Short Stories. Most of them are between 500 and 1000 words and all of them in Dutch.</p>
<ul>
{{- range .StoryYears -}}
<li><a href="{{ .Link }}">{{ .Name}}</a></li>
{{- end -}}
</ul>
</main>
</body>

View File

@ -0,0 +1,56 @@
{{ define "head" }}
<head>
<title>{{ .Title }} - ErikWinter.nl</title>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=10,user-scalable=yes" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="HandheldFriendly" content="true" />
<link rel="alternate" type="application/rss+xml" title="ErikWinter.nl" href="https://erikwinter.nl/index.xml" />
<style type="text/css">
@font-face { font-family: AmikoBold; src: url('/font/Amiko-Bold.ttf'); font-display: swap; }
@font-face { font-family: AmikoRegular; src: url('/font/Amiko-Regular.ttf'); font-display: swap; }
@font-face { font-family: AmikoSemiBold; src: url('/font/Amiko-SemiBold.ttf'); font-display: swap; }
@font-face { font-family: MerriWeatherRegular; src: url('/font/merriweather.regular.ttf'); font-display: swap; }
html { font-size: 18px; }
body { display: flex; flex-direction: column; max-width: 1000px; margin: auto; font-family: AmikoRegular; color: black; }
a { text-decoration: none; color: black; }
a:hover h2 { text-decoration: underline; }
code { line-height: 1.5rem; }
ul, li { margin: 0; padding: 0; }
li { list-style-type: none; }
#mainMenu { display: flex; width: 100%; justify-content: center; flex-wrap: wrap; border-bottom: 1px solid grey; font-family: AmikoSemiBold; }
#mainMenu ul { display: inline; margin: 0; padding: 15px 10px; }
#mainMenu li { display: inline; }
#mainMenu a { font-size: 1.4rem; text-align: center; margin: 0 20px; color: black; text-decoration: none; }
main { margin: 30px auto; width: 80%; }
main li { margin: 35px 20px;; }
main li h2 { display: inline; margin-right: 10px; margin-bottom: 1px; font-size: 1.4rem; }
main li .language { margin-right: 10px; font-size: 1.2rem; }
main li time { color: grey; }
main li p { margin-top: 10px; font-style: normal; color: black; text-decoration: none; }
main nav { margin: 0px 20px; }
main nav ul { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-start; align-content: center; margin: 30px 0px 0px 30px; }
/*main nav.tagList ul { justify-content: space-between; }*/
main nav li { display: inline; margin: 0; width: 140px; }
main nav li a { font-family: AmikoBold; margin: 1px 2px; color: black; }
main nav h2 { font-size: 1.4rem; }
main nav p { color: black; }
article { margin: auto; }
p, main article li { font-family: MerriWeatherRegular; line-height: 140%; }
article time, .tags, .tags a { font-family: AmikoRegular; color: grey; }
.tags, .tags li { display: inline; margin: 0; padding-left: 3px; }
p img { display: block; margin: 10px auto; }
#rss-feeds ~ p img { display: inline; margin: 0 3px 0 0; vertical-align: -0.6rem; }
h1 { font-size: 1.8rem; }
p a, article li a { font-weight: bold; font-family: AmikoBold }
article li { list-style-type: disc; margin: 5px 0 0 20px; }
article h2, nav h2 { margin-top: 40px; }
.greybox-dark, .greybox-light { margin-bottom: 30px; padding: 10px 30px; }
.greybox-dark { border-top: 1px solid grey; border-bottom: 1px solid grey; background-color: whitesmoke; }
.greybox-dark h2, .greybox-light h2 { margin: 0; text-align: center; }
audio { width: 100%; }
pre, code { background-color: whitesmoke; }
pre { width: auto; overflow: auto; }
</style>
<script data-goatcounter="https://erikwinter.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</head>
{{ end }}

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
{{- template "head" . -}}
<body>
{{- template "menu" -}}
<main>
<ul>
{{- range .Summaries -}}
<li>
<a href="{{ .Link }}">
<h2>{{ .Title }}</h2>
{{- if eq .Language "nl" -}}
<span class="language">&#127475;&#127473;</span>
{{- end -}}
<time datetime="{{ .DateShort }}">{{ .DateLong }}</time>
{{- .Summary -}}
</a>
</li>
{{- end -}}
</ul>
</main>
</body>
</html>

View File

@ -0,0 +1,16 @@
{{ define "menu" }}
<nav id="mainMenu">
<ul >
<li><a href="/">Recent</a></li>
<li><a href="/archive/">Archive</a></li>
<li><a href="/other/">Other &#127475;&#127473;</a></li>
<li><a href="/about/">About</a></li>
</ul>
</nav>
<section style="display: none;" class="h-card">
<span class="p-name">Erik Winter</span>
<span class="p-note">A Dutch sotware developer who likes open source, literature, music and a bunch of other things.</span>
<a class="u-url u-uid" href="https://erikwinter.nl"></a>
<a class="u-email" rel="me" href="mailto:ik@erikwinter.nl"></a>
</section>
{{ end }}

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
{{- template "head" . -}}
<body>
{{- template "menu" -}}
<main>
<article>
<section class="greybox-light">
<p><a href="https://crunchygranola.nl"><img src="crunchy.jpeg" alt="Crunchy Granola logo"></a></p>
<p>A <a href="https://crunchygranola.nl/">site</a> 🇳🇱 full of recipes for crunchy, tasty granolas that are nothing like the mundane stuff you buy at the store. Everything made from scratch, healthy ingredients, with options for all kinds of diets like gluten-free and keto. All recipes, photos, texts and design created by my wonderful girlfriend. I <em>-eh-</em> also did things.</p>
</section>
<section class="greybox-dark">
<p><img src="volca.png" alt="Volca Keys"></p>
<p>Some sounds I made. Some time ago.</p>
<audio controls>
<source src="christel%2039.mp3" type="audio/mp3">
</audio>
<audio controls>
<source src="werkeloos.mp3" type="audio/mp3">
</audio>
<audio controls>
<source src="volca%20testje.mp3" type="audio/mp3">
</audio>
</section>
<section class="greybox-light">
<p><a href="https://lowlands.nl/schrijfwedstrijd"><img src="lowlandswedstrijd.jpg" alt="Story illustration"></a></p>
<p>In 2015, one of my stories won the Lowlands Short Story contest. Because of that, it was featured in NRC, a Dutch national newspaper. You can read it <a href="https://www.nrc.nl/nieuws/2015/08/24/het-korte-nare-leven-van-arnold-scheepmaker-1526148-a1387897">here</a> 🇳🇱 on their site.</p>
</section>
<section class="greybox-dark">
<p><a href="https://web.archive.org/web/20121105034629/http://www.beginnenmetroken.nl/"><img src="beginnenmetroken.jpg" alt="Logo Beginnenmetroken.nl"></a></p>
<p>A long time ago, somewhere at the start of this century, I created <a href="http://www.BeginnenMetRoken.nl">www.BeginnenMetRoken.nl</a>, a satirical site that &ldquo;helped&rdquo; people to kickstart their smoking habit. Right in the middle of large campaings urging people to quit, it struck a nerve and went viral. Millions of pageviews, featured in several magazines. People still bring it up, twenty years later.</p>
<p>The site is gone, but it you can still view it <a href="https://web.archive.org/web/20121105034629/http://www.beginnenmetroken.nl/">here 🇳🇱</a> on Archive.org.</p>
</section>
</article>
</main>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
{{- template "head" . -}}
<body>
{{- template "menu" -}}
<main>
<article>
<h1>{{ .Title }}</h1>
<time datetime="{{ .DateShort }}">{{ .DateLong }}</time>
{{ .Content }}
</article>
</main>
</body>
</html>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>ErikWinter.nl</title>
<link>https://erikwinter.nl/</link>
<description>Activity on ErikWinter.nl</description>
<language>en-us</language>
<lastBuildDate>{{ .DateFormal }}</lastBuildDate>
<atom:link href="https://erikwinter.nl/index.xml" rel="self" type="application/rss+xml" />
{{- range .Posts -}}
<item>
<title>{{ .Title }}</title>
<link>{{ .Link }}</link>
<pubDate>{{ .DateFormal }}</pubDate>
<guid>{{ .Link }}</guid>
<description>{{ .Content }}</description>
</item>
{{- end -}}
</channel>
</rss>

93
site/block.go Normal file
View File

@ -0,0 +1,93 @@
package site
import (
"fmt"
"html"
"strings"
)
type BlockElement interface {
Text() string
BlockHTML() string
}
type Paragraph []InlineElement
func (p Paragraph) Text() string {
var text []string
for _, ie := range p {
text = append(text, ie.Text())
}
return strings.Join(text, " ")
}
func (p Paragraph) BlockHTML() string {
var body string
for _, ie := range p {
body += ie.InlineHTML()
}
return fmt.Sprintf("<p>%s</p>", body)
}
type SubTitle string
func (st SubTitle) Text() string { return string(st) }
func (st SubTitle) BlockHTML() string {
return fmt.Sprintf("<h2>%s</h2>", st)
}
type SubSubTitle string
func (st SubSubTitle) Text() string { return string(st) }
func (st SubSubTitle) BlockHTML() string {
return fmt.Sprintf("<h3>%s</h3>", st)
}
type CodeBlock string
func (cb CodeBlock) Text() string { return string(cb) }
func (cb CodeBlock) BlockHTML() string {
return fmt.Sprintf("<pre><code>%s</code></pre>", html.EscapeString(string(cb)))
}
type ListItem []InlineElement
func (li ListItem) Text() string {
var text []string
for _, ie := range li {
text = append(text, ie.Text())
}
return fmt.Sprintf("%s%s", LISTITEM_PREFIX, strings.Join(text, " "))
}
func (li ListItem) HTML() string {
var body string
for _, ie := range li {
body += ie.InlineHTML()
}
return fmt.Sprintf("<li>%s</li>", body)
}
type List []ListItem
func (l List) Text() string {
var items []string
for _, item := range l {
items = append(items, item.Text())
}
return strings.Join(items, "\n")
}
func (l List) BlockHTML() string {
var items []string
for _, item := range l {
items = append(items, item.HTML())
}
return fmt.Sprintf("<ul>\n%s\n</ul>", strings.Join(items, "\n"))
}

27
site/block_test.go Normal file
View File

@ -0,0 +1,27 @@
package site
import (
"fmt"
"testing"
"git.sr.ht/~ewintr/go-kit/test"
)
func TestParagraph(t *testing.T) {
p := Paragraph([]InlineElement{
PlainText("one "),
PlainText("two "),
PlainText("three"),
})
exp := "<p>one two three</p>"
test.Equals(t, exp, p.BlockHTML())
}
func TestSubTitle(t *testing.T) {
text := "text"
st := SubTitle(text)
exp := fmt.Sprintf("<h2>%s</h2>", text)
test.Equals(t, exp, st.BlockHTML())
}

18
site/html.go Normal file
View File

@ -0,0 +1,18 @@
package site
type HTMLPost struct {
Slug string
Title string
DateLong string
DateShort string
Content string
}
type HTMLSummary struct {
Link string
Title string
Language Language
DateShort string
DateLong string
Summary string
}

71
site/inline.go Normal file
View File

@ -0,0 +1,71 @@
package site
import (
"fmt"
"html"
)
type InlineType int
type InlineElement interface {
Text() string
InlineHTML() string
}
type PlainText string
func (pt PlainText) Text() string { return string(pt) }
func (pt PlainText) InlineHTML() string {
return html.EscapeString(string(pt))
}
type StrongText string
func (st StrongText) Text() string { return string(st) }
func (st StrongText) InlineHTML() string {
return fmt.Sprintf("<strong>%s</strong>", html.EscapeString(string(st)))
}
type EmpText string
func (et EmpText) Text() string { return string(et) }
func (et EmpText) InlineHTML() string {
return fmt.Sprintf("<em>%s</em>", html.EscapeString(string(et)))
}
type StrongEmpText string
func (set StrongEmpText) Text() string { return string(set) }
func (set StrongEmpText) InlineHTML() string {
return fmt.Sprintf("<strong><em>%s</em></strong>", html.EscapeString(string(set)))
}
type Link struct {
url string
title string
}
func NewLink(url, title string) Link {
return Link{
url: url,
title: title,
}
}
func (l Link) Text() string { return l.title }
func (l Link) InlineHTML() string {
return fmt.Sprintf("<a href=%q>%s</a>", l.url, html.EscapeString(l.title))
}
type CodeText string
func (ct CodeText) Text() string { return string(ct) }
func (ct CodeText) InlineHTML() string {
return fmt.Sprintf("<code>%s</code>", html.EscapeString(string(ct)))
}

41
site/inline_test.go Normal file
View File

@ -0,0 +1,41 @@
package site_test
import (
"fmt"
"testing"
"git.sr.ht/~ewintr/go-kit/test"
"git.sr.ht/~ewintr/shitty-ssg/site"
)
func TestPlainText(t *testing.T) {
text := "text"
pt := site.PlainText(text)
test.Equals(t, text, pt.InlineHTML())
}
func TestStrongText(t *testing.T) {
text := "text"
st := site.StrongText(text)
exp := fmt.Sprintf("<strong>%s</strong>", text)
test.Equals(t, exp, st.InlineHTML())
}
func TestEmpText(t *testing.T) {
text := "text"
et := site.EmpText(text)
exp := fmt.Sprintf("<em>%s</em>", text)
test.Equals(t, exp, et.InlineHTML())
}
func TestLink(t *testing.T) {
url := "http://example.com"
title := "link title"
link := site.NewLink(url, title)
exp := fmt.Sprintf("<a href=%q>%s</a>", url, title)
test.Equals(t, exp, link.InlineHTML())
}

59
site/meta.go Normal file
View File

@ -0,0 +1,59 @@
package site
const (
KIND_NOTE = Kind("note")
KIND_STORY = Kind("story")
KIND_ARTICLE = Kind("article")
KIND_INVALID = Kind("")
)
type Kind string
var pluralKind = map[Kind]string{
KIND_NOTE: "notes",
KIND_STORY: "stories",
KIND_ARTICLE: "articles",
}
func NewKind(kind string) Kind {
switch kind {
case "note":
return KIND_NOTE
case "story":
return KIND_STORY
case "article":
return KIND_ARTICLE
default:
return KIND_INVALID
}
}
const (
LANGUAGE_EN = Language("en")
LANGUAGE_NL = Language("nl")
LANGUAGE_INVALID = Language("")
)
type Language string
func NewLanguage(text string) Language {
switch text {
case "nl":
return LANGUAGE_NL
case "en":
fallthrough
default:
return LANGUAGE_EN
}
}
type Tag string
const (
DATE_SHORT DateFormat = iota
DATE_LONG
DATE_FORMAL //Sat, 12 Sep 2020 12:32:00 +0200
)
type DateFormat int

232
site/parser.go Normal file
View File

@ -0,0 +1,232 @@
package site
import (
"strings"
"time"
)
const (
TITLE_PREFIX = "= "
SUBTITLE_PREFIX = "== "
SUBSUBTITLE_PREFIX = "=== "
PARAGRAPH_SEPARATOR = "\n\n"
LINE_SEPARATOR = "\n"
CODE_PREFIX = "----\n"
CODE_SUFFIX = "\n----"
LISTITEM_PREFIX = "* "
PARAGRAPH_CONTINUATION = "\n+\n"
)
func NewPost(text string) Post {
post := Post{
Language: LANGUAGE_EN,
Tags: []Tag{},
}
// split up blocks
var pars []string
for _, s := range strings.Split(text, PARAGRAPH_SEPARATOR) {
if s == "" {
continue
}
pars = append(pars, s)
}
// actually, code blocks are allowed to have empty lines
var blocks []string
var inCode bool
var currentBlock string
for _, par := range pars {
switch {
case strings.HasPrefix(par, CODE_PREFIX) && strings.HasSuffix(par, CODE_SUFFIX):
blocks = append(blocks, par)
case !inCode && strings.HasPrefix(par, CODE_PREFIX):
inCode = true
currentBlock = par
case inCode && !strings.HasSuffix(par, CODE_SUFFIX):
currentBlock += PARAGRAPH_SEPARATOR + par
case inCode && strings.HasSuffix(par, CODE_SUFFIX):
currentBlock += PARAGRAPH_SEPARATOR + par
blocks = append(blocks, currentBlock)
inCode = false
currentBlock = ""
default:
blocks = append(blocks, par)
}
}
// interpret the blocks
for i, p := range blocks {
switch {
case i == 0 && strings.HasPrefix(p, TITLE_PREFIX):
ParseHeader(p, &post)
case strings.HasPrefix(p, SUBTITLE_PREFIX):
p = strings.TrimSpace(p)
s := strings.Split(p, SUBTITLE_PREFIX)
if len(s) == 1 || s[1] == "" {
continue
}
post.Content = append(post.Content, SubTitle(s[1]))
case strings.HasPrefix(p, SUBSUBTITLE_PREFIX):
p = strings.TrimSpace(p)
s := strings.Split(p, SUBSUBTITLE_PREFIX)
if len(s) == 1 || s[1] == "" {
continue
}
post.Content = append(post.Content, SubSubTitle(s[1]))
case isCodeBlock(p):
post.Content = append(post.Content, parseCodeBlock(p))
case strings.HasPrefix(p, LISTITEM_PREFIX):
p = strings.TrimSpace(p)
var items []ListItem
for i, ti := range strings.Split(p, LISTITEM_PREFIX) {
if i > 0 {
inline := ParseInline(strings.TrimSpace(ti))
items = append(items, ListItem(inline))
}
}
post.Content = append(post.Content, List(items))
default:
p = strings.TrimSpace(p)
post.Content = append(post.Content, Paragraph(ParseInline(p)))
}
}
return post
}
func isCodeBlock(par string) bool {
return strings.HasPrefix(par, CODE_PREFIX) && strings.HasSuffix(par, CODE_SUFFIX)
}
func parseCodeBlock(par string) CodeBlock {
ss := strings.Split(par, "\n")
ss = ss[1 : len(ss)-1]
content := strings.Join(ss, "\n")
return CodeBlock(content)
}
func ParseHeader(text string, post *Post) {
text = strings.TrimSpace(text)
lines := strings.Split(text, LINE_SEPARATOR)
for i, l := range lines {
switch {
case i == 0:
s := strings.Split(l, TITLE_PREFIX)
post.Title = s[1]
case isDate(l):
date, _ := time.Parse("2006-01-02", l)
post.Date = date
case strings.HasPrefix(l, ":kind:"):
s := strings.Split(l, ":")
post.Kind = NewKind(strings.TrimSpace(s[2]))
case strings.HasPrefix(l, ":language:"):
s := strings.Split(l, ":")
post.Language = NewLanguage(strings.TrimSpace(s[2]))
case strings.HasPrefix(l, ":tags:"):
s := strings.Split(l, ":")
t := strings.Split(s[2], ",")
for _, tag := range t {
post.Tags = append(post.Tags, Tag(strings.TrimSpace(tag)))
}
default:
post.Author = l
}
}
}
func isDate(text string) bool {
if _, err := time.Parse("2006-01-02", text); err == nil {
return true
}
return false
}
func ParseInline(text string) []InlineElement {
var e []InlineElement
ss := strings.Split(text, "")
var buffer, curWord, prevChar string
var strong, emp, code, linkTitle bool
wordStart := true
for _, s := range ss {
switch {
case (s == "_" && wordStart) || (s == "_" && emp):
e = addElement(e, buffer+curWord, strong, emp, code)
emp = !emp
buffer = ""
curWord = ""
case s == "*":
e = addElement(e, buffer+curWord, strong, emp, code)
buffer = ""
curWord = ""
strong = !strong
case s == "`":
e = addElement(e, buffer+curWord, strong, emp, code)
code = !code
buffer = ""
curWord = ""
case s == "[" && prevChar != "":
e = addElement(e, buffer, strong, emp, code)
linkTitle = true
curWord += s
case s == "]" && linkTitle:
e = addLink(e, curWord)
buffer = ""
curWord = ""
linkTitle = false
case s == " " && !linkTitle:
buffer += curWord + " "
curWord = ""
default:
curWord += s
}
prevChar = s
wordStart = false
if prevChar == " " {
wordStart = true
}
}
if len(buffer+curWord) > 0 {
e = addElement(e, buffer+curWord, false, false, false)
}
return e
}
func addLink(ies []InlineElement, linkText string) []InlineElement {
ss := strings.Split(linkText, "[")
if len(ss) < 2 {
ss = append(ss, "ERROR")
}
return append(ies, Link{url: ss[0], title: ss[1]})
}
func addElement(ies []InlineElement, text string, strong, emp, code bool) []InlineElement {
if len(text) == 0 {
return ies
}
var ne InlineElement
switch {
case code:
ne = CodeText(text)
case strong && emp:
ne = StrongEmpText(text)
case strong && !emp:
ne = StrongText(text)
case !strong && emp:
ne = EmpText(text)
default:
ne = PlainText(text)
}
return append(ies, ne)
}

247
site/parser_test.go Normal file
View File

@ -0,0 +1,247 @@
package site_test
import (
"fmt"
"testing"
"time"
"git.sr.ht/~ewintr/go-kit/test"
"git.sr.ht/~ewintr/shitty-ssg/site"
)
func TestNewPost(t *testing.T) {
one := "one"
two := "two"
three := "three"
ptOne := site.PlainText(one)
ptTwo := site.PlainText(two)
ptThree := site.PlainText(three)
for _, tc := range []struct {
name string
input string
exp site.Post
}{
{
name: "empty",
exp: site.Post{
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
},
},
{
name: "title",
input: "= Title",
exp: site.Post{
Title: "Title",
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
},
},
{
name: "header",
input: "= Title\nT. Test\n2020-10-27\n:tags:\ttag1, tag2\n:kind:\tnote\n:language:\tnl",
exp: site.Post{
Title: "Title",
Author: "T. Test",
Kind: site.KIND_NOTE,
Language: site.LANGUAGE_NL,
Tags: []site.Tag{
site.Tag("tag1"),
site.Tag("tag2"),
},
Date: time.Date(2020, time.October, 27, 0, 0, 0, 0, time.UTC),
},
},
{
name: "paragraphs",
input: fmt.Sprintf("%s\n\n%s\n\n%s", one, two, three),
exp: site.Post{
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
Content: []site.BlockElement{
site.Paragraph([]site.InlineElement{ptOne}),
site.Paragraph([]site.InlineElement{ptTwo}),
site.Paragraph([]site.InlineElement{ptThree}),
},
},
},
{
name: "subtitle",
input: "== Subtitle",
exp: site.Post{
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
Content: []site.BlockElement{
site.SubTitle("Subtitle"),
},
},
},
{
name: "code block",
input: "----\nsome code\nmore code\n----",
exp: site.Post{
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
Content: []site.BlockElement{
site.CodeBlock("some code\nmore code"),
},
},
},
{
name: "code block with empty lines",
input: "----\nsome code\n\nmore code\n----",
exp: site.Post{
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
Content: []site.BlockElement{
site.CodeBlock("some code\n\nmore code"),
},
},
},
{
name: "list",
input: "* item 1\n* item 2\n* *item 3*\n",
exp: site.Post{
Tags: []site.Tag{},
Language: site.LANGUAGE_EN,
Content: []site.BlockElement{
site.List{
site.ListItem([]site.InlineElement{site.PlainText("item 1")}),
site.ListItem([]site.InlineElement{site.PlainText("item 2")}),
site.ListItem([]site.InlineElement{site.StrongText("item 3")}),
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
act := site.NewPost(tc.input)
test.Equals(t, tc.exp, act)
})
}
}
func TestPostBodyHTML(t *testing.T) {
text := `= Title
Some text. With some *strong*. And a http://example.com[link].
== A Sub Title
And some more text.
`
post := site.NewPost(text)
act := post.HTMLPost()
exp := &site.HTMLPost{
Slug: "title",
Title: "Title",
DateLong: "January 1, 0001",
DateShort: "0001-01-01 00:00:00",
Content: `<p>Some text. With some <strong>strong</strong>. And a <a href="http://example.com">link</a>.</p>
<h2>A Sub Title</h2>
<p>And some more text.</p>
`,
}
test.Equals(t, exp, act)
}
func TestParseInline(t *testing.T) {
for _, tc := range []struct {
name string
input string
exp []site.InlineElement
}{{
name: "empty",
},
{
name: "plain",
input: "some test text",
exp: []site.InlineElement{
site.PlainText("some test text")},
},
{
name: "strong",
input: "*some strong text*",
exp: []site.InlineElement{
site.StrongText("some strong text"),
},
},
{
name: "strong in plain",
input: "some *strong* text",
exp: []site.InlineElement{
site.PlainText("some "),
site.StrongText("strong"),
site.PlainText(" text"),
},
},
{
name: "emphasis",
input: "_some emphasized text_",
exp: []site.InlineElement{
site.EmpText("some emphasized text"),
},
},
{
name: "emphasis in plain",
input: "some _emphasized_ text",
exp: []site.InlineElement{
site.PlainText("some "),
site.EmpText("emphasized"),
site.PlainText(" text"),
},
},
{
name: "emp and strong in plain",
input: "some _*special*_ text",
exp: []site.InlineElement{
site.PlainText("some "),
site.StrongEmpText("special"),
site.PlainText(" text"),
},
},
{
name: "link",
input: "a link[title] somewhere",
exp: []site.InlineElement{
site.PlainText("a "),
site.NewLink("link", "title"),
site.PlainText(" somewhere"),
},
},
{
name: "code",
input: "`command`",
exp: []site.InlineElement{
site.CodeText("command"),
},
},
{
name: "code in plain",
input: "some `code` in text",
exp: []site.InlineElement{
site.PlainText("some "),
site.CodeText("code"),
site.PlainText(" in text"),
},
},
{
name: "link with underscore",
input: "https://example.com/some_url[some url]",
exp: []site.InlineElement{
site.NewLink("https://example.com/some_url", "some url"),
},
},
} {
t.Run(tc.name, func(t *testing.T) {
act := site.ParseInline(tc.input)
test.Equals(t, tc.exp, act)
})
}
}

125
site/post.go Normal file
View File

@ -0,0 +1,125 @@
package site
import (
"errors"
"fmt"
"html"
"path"
"strconv"
"strings"
"time"
"git.sr.ht/~ewintr/go-kit/slugify"
)
var (
ErrInvalidPost = errors.New("invalid post")
)
type Post struct {
Title string
Author string
Kind Kind
Language Language
Path string
Date time.Time
Tags []Tag
Content []BlockElement
}
func (p Post) Slug() string {
return slugify.Slugify(p.Title)
}
func (p *Post) Year() string {
return strconv.Itoa(p.Date.Year())
}
func (p *Post) Link() string {
return fmt.Sprintf("%s/", path.Join("/", pluralKind[p.Kind], p.Year(), p.Slug()))
}
func (p *Post) FullLink() string {
return fmt.Sprintf("https://erikwinter.nl/%s", p.Link())
}
func (p *Post) HTMLSummary() *HTMLSummary {
summary := ""
if len(p.Content) > 0 {
summary = fmt.Sprintf("<p>%s...</p>", truncateOnSpace(p.Content[0].Text(), 150))
}
return &HTMLSummary{
Link: p.Link(),
Title: p.Title,
Language: p.Language,
DateLong: p.FormattedDate(DATE_LONG),
DateShort: p.FormattedDate(DATE_SHORT),
Summary: summary,
}
}
func (p *Post) HTMLPost() *HTMLPost {
var content string
for _, be := range p.Content {
content += fmt.Sprintf("%s\n", be.BlockHTML())
}
return &HTMLPost{
Slug: p.Slug(),
Title: html.EscapeString(p.Title),
DateLong: p.FormattedDate(DATE_LONG),
DateShort: p.FormattedDate(DATE_SHORT),
Content: content,
}
}
func (p *Post) XMLPost() *XMLPost {
var content string
for _, be := range p.Content {
content += fmt.Sprintf("%s\n", html.EscapeString(be.BlockHTML()))
}
return &XMLPost{
Link: p.FullLink(),
Title: html.EscapeString(p.Title),
DateFormal: p.FormattedDate(DATE_FORMAL),
Content: content,
}
}
func (p Post) FormattedDate(format DateFormat) string {
switch {
case format == DATE_LONG && p.Language == LANGUAGE_NL:
nlMonth := [...]string{"januari", "februari", "maart",
"april", "mei", "juni", "juli", "augustus", "september",
"oktober", "november", "december",
}
return fmt.Sprintf("%d %s %d", p.Date.Day(), nlMonth[p.Date.Month()-1], p.Date.Year())
case format == DATE_LONG && p.Language == LANGUAGE_EN:
return p.Date.Format("January 2, 2006")
case format == DATE_FORMAL:
return p.Date.Format(time.RFC1123Z)
case format == DATE_SHORT:
fallthrough
default:
return p.Date.Format("2006-01-02 00:00:00")
}
}
func truncateOnSpace(text string, maxChars int) string {
if len(text) <= maxChars {
return text
}
shortText := ""
ss := strings.Split(text, " ")
for _, s := range ss {
if len(shortText+" "+s) > maxChars {
break
}
shortText += " " + s
}
return shortText
}

113
site/posts.go Normal file
View File

@ -0,0 +1,113 @@
package site
import "sort"
type Posts []Post
func (p Posts) Len() int { return len(p) }
func (p Posts) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p Posts) Less(i, j int) bool { return p[i].Date.After(p[j].Date) }
func (p Posts) Sort() Posts {
sort.Sort(p)
return p
}
func (p Posts) FilterByKind(wanted Kind) Posts {
pList := Posts{}
for _, post := range p {
if post.Kind == wanted {
pList = append(pList, post)
}
}
return pList
}
func (p Posts) FilterByYear(year string) Posts {
pList := Posts{}
for _, post := range p {
if post.Year() == year {
pList = append(pList, post)
}
}
return pList
}
func (p Posts) FilterByTag(wanted Tag) Posts {
pList := Posts{}
POSTS:
for _, post := range p {
for _, tag := range post.Tags {
if tag == wanted {
pList = append(pList, post)
continue POSTS
}
}
}
return pList
}
func (p Posts) Limit(limit int) Posts {
if len(p) <= limit {
return p
}
return p[:limit]
}
func (p Posts) YearList() []string {
fullList := []string{}
for _, post := range p {
fullList = append(fullList, post.Year())
}
list := removeDuplicates(fullList)
sort.Strings(list)
return list
}
func (p Posts) TagList() []string {
fullList := []string{}
for _, post := range p {
for _, tag := range post.Tags {
fullList = append(fullList, string(tag))
}
}
list := removeDuplicates(fullList)
sort.Strings(list)
return list
}
func (p Posts) HTMLSummaries() []*HTMLSummary {
summaries := []*HTMLSummary{}
for _, post := range p {
summaries = append(summaries, post.HTMLSummary())
}
return summaries
}
func removeDuplicates(fullList []string) []string {
list := []string{}
for _, item := range fullList {
isNew := true
for _, li := range list {
if item == li {
isNew = false
}
}
if isNew {
list = append(list, item)
}
}
return list
}

254
site/render.go Normal file
View File

@ -0,0 +1,254 @@
package site
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"time"
)
const dirMode = os.ModeDir | 0755
func resetTarget(targetPath string) error {
if err := os.RemoveAll(targetPath); err != nil {
return err
}
return os.Mkdir(targetPath, dirMode)
}
func moveResources(targetPath, resourcesPath string) error {
for _, dir := range []string{"css", "font"} {
srcPath := filepath.Join(resourcesPath, dir)
destPath := filepath.Join(targetPath, dir)
if err := copyFiles(filepath.Join(srcPath, "*"), destPath); err != nil {
return err
}
}
return nil
}
func renderStaticPages(targetPath string, statics []*StaticPage) error {
for _, static := range statics {
destPath := filepath.Join(targetPath, static.Name)
if err := os.MkdirAll(destPath, dirMode); err != nil {
return err
}
pageFile, err := os.Create(filepath.Join(destPath, "index.html"))
if err != nil {
return err
}
defer pageFile.Close()
data := struct {
Title string
}{
Title: strings.Title(static.Name),
}
if err := static.Template.Execute(pageFile, data); err != nil {
return err
}
if err := copyFiles(filepath.Join(static.SourcePath, "*"), destPath); err != nil {
return err
}
}
return nil
}
func renderHome(targetPath string, tpl *template.Template, posts Posts) error {
data := struct {
Title string
Summaries []*HTMLSummary
}{
Title: "Recent",
Summaries: posts.HTMLSummaries(),
}
hPath := filepath.Join(targetPath, "index.html")
homeFile, err := os.Create(hPath)
if err != nil {
return err
}
defer homeFile.Close()
return tpl.Execute(homeFile, data)
}
func renderArchive(targetPath string, tpl *template.Template, title string, posts Posts) error {
archPath := filepath.Join(targetPath, "archive")
if err := os.MkdirAll(archPath, dirMode); err != nil {
return err
}
archFile, err := os.Create(filepath.Join(archPath, "index.html"))
if err != nil {
return err
}
type link struct {
Name string
Link string
}
tags := []link{}
for _, tag := range posts.TagList() {
tags = append(tags, link{
Name: tag,
Link: fmt.Sprintf("%s/", path.Join("/tags", tag)),
})
}
yearLinks := map[Kind][]link{
KIND_ARTICLE: {},
KIND_NOTE: {},
KIND_STORY: {},
}
for kind := range yearLinks {
for _, year := range posts.FilterByKind(kind).YearList() {
yearLinks[kind] = append(yearLinks[kind], link{
Name: year,
Link: fmt.Sprintf("%s/", path.Join("/", pluralKind[kind], year)),
})
}
}
data := struct {
Title string
Tags []link
ArticleYears []link
NoteYears []link
StoryYears []link
}{
Title: title,
Tags: tags,
ArticleYears: yearLinks[KIND_ARTICLE],
NoteYears: yearLinks[KIND_NOTE],
StoryYears: yearLinks[KIND_STORY],
}
return tpl.Execute(archFile, data)
}
func renderListings(targetPath string, tpl *template.Template, posts Posts) error {
for _, kind := range []Kind{KIND_NOTE, KIND_STORY, KIND_ARTICLE} {
for _, year := range posts.FilterByKind(kind).YearList() {
title := fmt.Sprintf("%s in %s", strings.Title(pluralKind[kind]), year)
summaries := posts.FilterByKind(kind).FilterByYear(year).HTMLSummaries()
path := filepath.Join(targetPath, pluralKind[kind], year)
if err := renderListing(path, tpl, title, summaries); err != nil {
return err
}
}
}
for _, tag := range posts.TagList() {
title := fmt.Sprintf("Posts Tagged with \"%s\"", tag)
summaries := posts.FilterByTag(Tag(tag)).HTMLSummaries()
path := filepath.Join(targetPath, "tags", tag)
if err := renderListing(path, tpl, title, summaries); err != nil {
return err
}
}
return nil
}
func renderListing(path string, tpl *template.Template, title string, summaries []*HTMLSummary) error {
data := struct {
Title string
Summaries []*HTMLSummary
}{
Title: title,
Summaries: summaries,
}
if err := os.MkdirAll(path, dirMode); err != nil {
return err
}
lPath := filepath.Join(path, "index.html")
f, err := os.Create(lPath)
if err != nil {
return err
}
defer f.Close()
return tpl.Execute(f, data)
}
func renderPosts(targetPath string, tpl *template.Template, posts Posts) error {
for _, post := range posts {
data := post.HTMLPost()
if data.Slug == "" {
return ErrInvalidPost
}
path := filepath.Join(targetPath, pluralKind[post.Kind], post.Year(), data.Slug)
if err := os.MkdirAll(path, dirMode); err != nil {
return err
}
nPath := filepath.Join(path, "index.html")
f, err := os.Create(nPath)
if err != nil {
return err
}
defer f.Close()
if err := tpl.Execute(f, data); err != nil {
return err
}
}
return nil
}
func renderRSS(targetPath string, tpl *template.Template, posts Posts) error {
rssPath := filepath.Join(targetPath, "index.xml")
rssFile, err := os.Create(rssPath)
if err != nil {
return err
}
defer rssFile.Close()
var xmlPosts []*XMLPost
for _, p := range posts.Limit(10) {
xmlPosts = append(xmlPosts, p.XMLPost())
}
data := struct {
DateFormal string
Posts []*XMLPost
}{
DateFormal: time.Now().Format(time.RFC1123Z),
Posts: xmlPosts,
}
return tpl.Execute(rssFile, data)
}
func copyFiles(srcPattern, destPath string) error {
filePaths, err := filepath.Glob(srcPattern)
if err != nil {
return err
}
if err := os.MkdirAll(destPath, dirMode); err != nil {
return err
}
for _, fPath := range filePaths {
destFPath := filepath.Join(destPath, filepath.Base(fPath))
content, err := ioutil.ReadFile(fPath)
if err != nil {
return err
}
if err := ioutil.WriteFile(destFPath, content, 0644); err != nil {
return err
}
}
return nil
}

118
site/site.go Normal file
View File

@ -0,0 +1,118 @@
package site
import (
"fmt"
"io/ioutil"
"path/filepath"
"text/template"
)
type StaticPage struct {
Name string
Template *template.Template
SourcePath string
}
type Site struct {
resourcesPath string
templates map[string]*template.Template
posts Posts
staticPages []*StaticPage
}
func New(resourcesPath string) (*Site, error) {
templates, err := parseTemplates(resourcesPath)
if err != nil {
return &Site{}, err
}
staticPages := []*StaticPage{}
for _, stName := range []string{"other", "about"} {
staticPages = append(staticPages, &StaticPage{
Name: stName,
Template: templates[stName],
SourcePath: filepath.Join(resourcesPath, stName),
})
}
return &Site{
resourcesPath: resourcesPath,
templates: templates,
posts: []Post{},
staticPages: staticPages,
}, nil
}
func (s *Site) AddFilePost(fPath string) error {
content, err := ioutil.ReadFile(fPath)
if err != nil {
return err
}
s.posts = append(s.posts, NewPost(string(content)))
return nil
}
func (s *Site) AddFolderPost(kind Kind, fPath string) error {
// TODO implement
return nil
}
func (s *Site) RenderHTML(targetPath string) error {
posts := s.posts.Sort()
if err := resetTarget(targetPath); err != nil {
return err
}
if err := moveResources(targetPath, s.resourcesPath); err != nil {
return err
}
if err := renderStaticPages(targetPath, s.staticPages); err != nil {
return err
}
if err := renderArchive(targetPath, s.templates["archive"], "Archive", posts); err != nil {
return err
}
if err := renderHome(targetPath, s.templates["list"], posts.Limit(10)); err != nil {
return err
}
if err := renderListings(targetPath, s.templates["list"], posts); err != nil {
return err
}
if err := renderPosts(targetPath, s.templates["post"], posts); err != nil {
return err
}
if err := renderRSS(targetPath, s.templates["rss"], posts); err != nil {
return err
}
return nil
}
func parseTemplates(resourcesPath string) (map[string]*template.Template, error) {
templates := map[string]*template.Template{}
tPath := filepath.Join(resourcesPath, "template")
for _, tName := range []string{"post", "list", "archive", "other", "about"} {
var tFiles []string
for _, tf := range []string{tName, "head", "menu"} {
tFiles = append(tFiles, filepath.Join(tPath, fmt.Sprintf("%s.gohtml", tf)))
}
tpl, err := template.ParseFiles(tFiles...)
if err != nil {
return map[string]*template.Template{}, err
}
templates[tName] = tpl
}
rss, err := template.ParseFiles(filepath.Join(tPath, "rss.goxml"))
if err != nil {
return map[string]*template.Template{}, err
}
templates["rss"] = rss
return templates, nil
}

8
site/xml.go Normal file
View File

@ -0,0 +1,8 @@
package site
type XMLPost struct {
Link string
Title string
DateFormal string
Content string
}