Compare commits
	
		
			27 Commits
		
	
	
		
			04e19f5186
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						486b58525f
	
				 | 
					
					
						|||
| 
						
						
							
						
						c3cc608570
	
				 | 
					
					
						|||
| 
						
						
							
						
						d643187333
	
				 | 
					
					
						|||
| 
						
						
							
						
						103704b183
	
				 | 
					
					
						|||
| 
						
						
							
						
						18e8e11ad4
	
				 | 
					
					
						|||
| 
						
						
							
						
						1528ed2db0
	
				 | 
					
					
						|||
| 
						
						
							
						
						5f0d5bca70
	
				 | 
					
					
						|||
| 
						
						
							
						
						442fa5d660
	
				 | 
					
					
						|||
| 
						
						
							
						
						8b376694d3
	
				 | 
					
					
						|||
| 
						
						
							
						
						22e3861851
	
				 | 
					
					
						|||
| 
						
						
							
						
						9603456cd6
	
				 | 
					
					
						|||
| 
						
						
							
						
						b832a38ca6
	
				 | 
					
					
						|||
| 
						
						
							
						
						6353dd156a
	
				 | 
					
					
						|||
| 
						
						
							
						
						7a2ea02c8d
	
				 | 
					
					
						|||
| 
						
						
							
						
						bafd5ef221
	
				 | 
					
					
						|||
| 
						
						
							
						
						ca245e4aca
	
				 | 
					
					
						|||
| 
						
						
							
						
						c3905349b0
	
				 | 
					
					
						|||
| 
						
						
							
						
						f9e1f9a244
	
				 | 
					
					
						|||
| 
						
						
							
						
						4aab0b22ae
	
				 | 
					
					
						|||
| 
						
						
							
						
						5ab2977548
	
				 | 
					
					
						|||
| 
						
						
							
						
						a927713a81
	
				 | 
					
					
						|||
| 
						
						
							
						
						5ae8c24b8d
	
				 | 
					
					
						|||
| 
						
						
							
						
						ef24d7980c
	
				 | 
					
					
						|||
| 
						
						
							
						
						6228693b22
	
				 | 
					
					
						|||
| 
						
						
							
						
						be27f00685
	
				 | 
					
					
						|||
| 
						
						
							
						
						61083027a3
	
				 | 
					
					
						|||
| 
						
						
							
						
						5b432fcc0b
	
				 | 
					
					
						
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,6 +2,7 @@
 | 
			
		||||
/hid/hid
 | 
			
		||||
/hnc/hnc
 | 
			
		||||
/hpcu/hpcu
 | 
			
		||||
/hswg/hswg
 | 
			
		||||
/ht/ht
 | 
			
		||||
/prototypes/tls-autodetect
 | 
			
		||||
/prototypes/xgb-draw
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
Copyright (c) 2018, Přemysl Eric Janouch <p@janouch.name>
 | 
			
		||||
Copyright (c) 2018 - 2022, Přemysl Eric Janouch <p@janouch.name>
 | 
			
		||||
 | 
			
		||||
Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
purpose with or without fee is hereby granted.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								README.adoc
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								README.adoc
									
									
									
									
									
								
							@@ -34,12 +34,7 @@ figured out it would make sense:
 | 
			
		||||
 - hbfe - bitmap font editor
 | 
			
		||||
 - he   - text editor
 | 
			
		||||
 - hfm  - file manager
 | 
			
		||||
 - hib  - IRC bouncer
 | 
			
		||||
 - hic  - IRC client
 | 
			
		||||
 - hid  - IRC daemon
 | 
			
		||||
 - hiv  - image viewer
 | 
			
		||||
 - hm   - mail client
 | 
			
		||||
 - hmpc - MPD client
 | 
			
		||||
 - hnc  - netcat-alike
 | 
			
		||||
 - ho   - all-powerful organizer
 | 
			
		||||
 - hsm  - system monitor
 | 
			
		||||
@@ -61,26 +56,11 @@ permeating the entire list.
 | 
			
		||||
Some information is omitted from these descriptions and lies either in my head
 | 
			
		||||
or in my other notes.
 | 
			
		||||
 | 
			
		||||
hid -- IRC daemon
 | 
			
		||||
~~~~~~~~~~~~~~~~~
 | 
			
		||||
This project is unimportant by itself, its sole purpose is to gain experience
 | 
			
		||||
with Go on something that I have already done and understand well.  Nothing
 | 
			
		||||
beyond achieving feature parity is in the initial scope.
 | 
			
		||||
 | 
			
		||||
One possibility of complicating would be adding simple WebSocket listeners but
 | 
			
		||||
that's already been done for me https://github.com/kiwiirc/webircgateway and
 | 
			
		||||
it's even in Go, I just need to set up kiwiirc.
 | 
			
		||||
 | 
			
		||||
Later, when we have a pleasant IRC client, implement either the P10 or the TS6
 | 
			
		||||
server-linking protocol and make atheme work with a generic module.
 | 
			
		||||
Alternatively add support for plugins.  The goal is to allow creating integrated
 | 
			
		||||
bridges to various public forums.
 | 
			
		||||
 | 
			
		||||
hnc -- netcat-alike
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
The result of testing hid with telnet, OpenSSL s_client, OpenBSD nc, GNU nc and
 | 
			
		||||
Ncat is that neither of them can properly shutdown the connection.  We need
 | 
			
		||||
a good implementation with TLS support.
 | 
			
		||||
The result of testing xK/xS with telnet, OpenSSL s_client, OpenBSD nc, GNU nc,
 | 
			
		||||
and Ncat is that neither of them can properly shutdown the connection.
 | 
			
		||||
We need a good implementation with TLS support.
 | 
			
		||||
 | 
			
		||||
hpcu -- PRIMARY-CLIPBOARD unifier
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
@@ -96,29 +76,12 @@ Only UTF8_STRING-convertible selections are synchronized.
 | 
			
		||||
 | 
			
		||||
hswg -- static website generator
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
Wraps libasciidoc to make it understand more syntax, namely two-line/underlined
 | 
			
		||||
titles, and can be run either as an AsciiDoc processor for my Gitea, or as
 | 
			
		||||
a trivial wiki-like site generator.
 | 
			
		||||
link:hswg/README.adoc[See hswg's README for details.]
 | 
			
		||||
 | 
			
		||||
ht -- terminal emulator
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
Similar scope to st(1).  Clever display of internal padding for better looks.
 | 
			
		||||
 | 
			
		||||
hib and hic -- IRC bouncer and client
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
An IRC client is a good starting application for building a GUI toolkit, as the
 | 
			
		||||
UI can afford to be truly minimalistic and most of it is text.
 | 
			
		||||
 | 
			
		||||
To resolve an issue I have with my current IRC client, the client is going to be
 | 
			
		||||
split into two parts: a bouncer that manages all connections and state, and
 | 
			
		||||
a separate GUI that communicates with the backend over TLS/WebSocket.  Perhaps
 | 
			
		||||
only the per-buffer input line is going to be desynchronized.
 | 
			
		||||
 | 
			
		||||
https://godoc.org/github.com/gorilla/websocket
 | 
			
		||||
 | 
			
		||||
The higher-level client-server API could be made rather generic to allow for
 | 
			
		||||
smooth integration with non-IRC "backends" such as Slack or Mattermost.
 | 
			
		||||
 | 
			
		||||
he -- text editor
 | 
			
		||||
~~~~~~~~~~~~~~~~~
 | 
			
		||||
VIM controls, no scripting, no syntax highlight, single-file, made for
 | 
			
		||||
@@ -164,17 +127,6 @@ Instead of ICU we may use x/text/collate and that's about everything we need.
 | 
			
		||||
Since we have our own format, we may expect the index to be ordered by the
 | 
			
		||||
locale's rules, assuming they don't change between versions.
 | 
			
		||||
 | 
			
		||||
hmpc -- MPD client
 | 
			
		||||
~~~~~~~~~~~~~~~~~~
 | 
			
		||||
Here the focus will be on the GUI toolkit.  I don't expect this application to
 | 
			
		||||
get big, since its predecessor nncmpp isn't either.  The daemon takes care of
 | 
			
		||||
all complex stuff.  It would be nice to add lyrics and search later, though.
 | 
			
		||||
 | 
			
		||||
hiv -- image viewer
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
JPG, PNG, first frame of GIF.  Zoom.  Going through adjacent files in directory
 | 
			
		||||
using cursor keys.  Possibly a dialog with image metadata.
 | 
			
		||||
 | 
			
		||||
hfm -- file manager
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
All we need to achieve here is replace Midnight Commander, which besides the
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								go.mod
									
									
									
									
									
								
							@@ -1,14 +1,26 @@
 | 
			
		||||
module janouch.name/haven
 | 
			
		||||
 | 
			
		||||
go 1.14
 | 
			
		||||
go 1.17
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802
 | 
			
		||||
	github.com/alecthomas/chroma v0.8.1 // indirect
 | 
			
		||||
	github.com/bytesparadise/libasciidoc v0.6.0
 | 
			
		||||
	github.com/dlclark/regexp2 v1.2.1 // indirect
 | 
			
		||||
	github.com/bytesparadise/libasciidoc v0.7.1-0.20221008082129-967103fe8df6
 | 
			
		||||
	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
 | 
			
		||||
	github.com/nxadm/tail v1.4.5 // indirect
 | 
			
		||||
	github.com/onsi/ginkgo v1.14.1 // indirect
 | 
			
		||||
	golang.org/x/image v0.0.0-20190802002840-cff245a6509b
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require github.com/sirupsen/logrus v1.8.1 // indirect
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/alecthomas/chroma/v2 v2.3.0 // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
			
		||||
	github.com/dlclark/regexp2 v1.4.0 // indirect
 | 
			
		||||
	github.com/kr/pretty v0.1.0 // indirect
 | 
			
		||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
 | 
			
		||||
	golang.org/x/text v0.3.7 // indirect
 | 
			
		||||
	golang.org/x/tools v0.1.9 // indirect
 | 
			
		||||
	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
 | 
			
		||||
	gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										153
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								go.sum
									
									
									
									
									
								
							@@ -14,18 +14,12 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
			
		||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
 | 
			
		||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 | 
			
		||||
github.com/DataDog/gostackparse v0.5.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
 | 
			
		||||
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/go.mod h1:gHw09mkX1Qp80JlYbmN9L3+4R5o6DJJ3GRShh+AICNc=
 | 
			
		||||
github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE=
 | 
			
		||||
github.com/alecthomas/chroma v0.8.1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
 | 
			
		||||
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/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
 | 
			
		||||
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/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U=
 | 
			
		||||
github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw=
 | 
			
		||||
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
 | 
			
		||||
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
 | 
			
		||||
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=
 | 
			
		||||
@@ -35,9 +29,12 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 | 
			
		||||
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/bytesparadise/libasciidoc v0.7.1-0.20221008082129-967103fe8df6 h1:H6OENzfxMVi4XJvFZWpbnttN5ncGnhC2qS15slyDdbw=
 | 
			
		||||
github.com/bytesparadise/libasciidoc v0.7.1-0.20221008082129-967103fe8df6/go.mod h1:Q2ZeBQ1fko5+NTUTs8rGu9gjTtbVaD6Qxg37GOPYdN4=
 | 
			
		||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 | 
			
		||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 | 
			
		||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 | 
			
		||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 | 
			
		||||
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=
 | 
			
		||||
@@ -45,21 +42,16 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
 | 
			
		||||
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/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 | 
			
		||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 | 
			
		||||
github.com/dlclark/regexp2 v1.2.1 h1:Ff/S0snjr1oZHUNOkvA/gP6KUaMg5vDDl3Qnhjnwgm8=
 | 
			
		||||
github.com/dlclark/regexp2 v1.2.1/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 | 
			
		||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
 | 
			
		||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 | 
			
		||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 | 
			
		||||
github.com/felixge/fgtrace v0.1.0/go.mod h1:VYPh/jE5zczuRiQge0AtcpNmcLhV/epE/wpfVYQALlU=
 | 
			
		||||
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=
 | 
			
		||||
@@ -67,6 +59,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
 | 
			
		||||
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/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
 | 
			
		||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 | 
			
		||||
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/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 | 
			
		||||
@@ -84,19 +78,22 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
 | 
			
		||||
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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 | 
			
		||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 | 
			
		||||
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/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 | 
			
		||||
github.com/google/go-cmp v0.5.5/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/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
 | 
			
		||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
			
		||||
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=
 | 
			
		||||
@@ -126,6 +123,7 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
 | 
			
		||||
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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 | 
			
		||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 | 
			
		||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 | 
			
		||||
@@ -136,18 +134,14 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
 | 
			
		||||
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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 | 
			
		||||
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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
			
		||||
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-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 | 
			
		||||
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=
 | 
			
		||||
@@ -158,33 +152,31 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 | 
			
		||||
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/mna/pigeon v1.1.0 h1:EjlvVbkGnNGemf8OrjeJX0nH8orujY/HkJgzJtd7kxc=
 | 
			
		||||
github.com/mna/pigeon v1.1.0/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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 | 
			
		||||
github.com/nxadm/tail v1.4.5 h1:obHEce3upls1IBn1gTw/o7bCv7OJb6Ib/o7wNO+4eKw=
 | 
			
		||||
github.com/nxadm/tail v1.4.5/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 | 
			
		||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 | 
			
		||||
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/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
 | 
			
		||||
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
 | 
			
		||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
 | 
			
		||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
 | 
			
		||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 | 
			
		||||
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
 | 
			
		||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
 | 
			
		||||
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/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
 | 
			
		||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 | 
			
		||||
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/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
 | 
			
		||||
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=
 | 
			
		||||
@@ -201,41 +193,45 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
 | 
			
		||||
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/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
 | 
			
		||||
github.com/sirupsen/logrus v1.8.1/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 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 | 
			
		||||
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 | 
			
		||||
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/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 | 
			
		||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 | 
			
		||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 | 
			
		||||
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=
 | 
			
		||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 | 
			
		||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 | 
			
		||||
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/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 | 
			
		||||
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=
 | 
			
		||||
@@ -264,8 +260,10 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
 | 
			
		||||
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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
			
		||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
 | 
			
		||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 | 
			
		||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
@@ -282,8 +280,11 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
 | 
			
		||||
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/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 | 
			
		||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 | 
			
		||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 | 
			
		||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
 | 
			
		||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
			
		||||
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=
 | 
			
		||||
@@ -292,7 +293,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 | 
			
		||||
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/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/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=
 | 
			
		||||
@@ -300,7 +302,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
 | 
			
		||||
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=
 | 
			
		||||
@@ -312,17 +313,25 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
			
		||||
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-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/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/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
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/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 | 
			
		||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
			
		||||
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=
 | 
			
		||||
@@ -344,8 +353,10 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
 | 
			
		||||
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/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 | 
			
		||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 | 
			
		||||
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
 | 
			
		||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 | 
			
		||||
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=
 | 
			
		||||
@@ -377,27 +388,29 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ
 | 
			
		||||
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=
 | 
			
		||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 | 
			
		||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 | 
			
		||||
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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 | 
			
		||||
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 | 
			
		||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 | 
			
		||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 | 
			
		||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
LC_ALL=C exec awk '
 | 
			
		||||
	/^[0-9]+ *(ERR|RPL)_[A-Z]+ *".*"$/ {
 | 
			
		||||
		match($0, /".*"/);
 | 
			
		||||
		ids[$1] = $2;
 | 
			
		||||
		texts[$2] = substr($0, RSTART, RLENGTH);
 | 
			
		||||
	}
 | 
			
		||||
	END {
 | 
			
		||||
		print "package " ENVIRON["GOPACKAGE"] "\n\nconst ("
 | 
			
		||||
		for (i in ids)
 | 
			
		||||
			printf("\t%s = %s\n", ids[i], i)
 | 
			
		||||
		print ")\n\nvar defaultReplies = map[int]string{"
 | 
			
		||||
		for (i in ids)
 | 
			
		||||
			print "\t" ids[i] ": " texts[ids[i]] ","
 | 
			
		||||
		print "}"
 | 
			
		||||
	}'
 | 
			
		||||
@@ -1,87 +0,0 @@
 | 
			
		||||
1 RPL_WELCOME ":Welcome to the Internet Relay Network %s!%s@%s"
 | 
			
		||||
2 RPL_YOURHOST ":Your host is %s, running version %s"
 | 
			
		||||
3 RPL_CREATED ":This server was created %s"
 | 
			
		||||
4 RPL_MYINFO "%s %s %s %s"
 | 
			
		||||
5 RPL_ISUPPORT "%s :are supported by this server"
 | 
			
		||||
211 RPL_STATSLINKINFO "%s %d %d %d %d %d %d"
 | 
			
		||||
212 RPL_STATSCOMMANDS "%s %d %d %d"
 | 
			
		||||
219 RPL_ENDOFSTATS "%c :End of STATS report"
 | 
			
		||||
221 RPL_UMODEIS "+%s"
 | 
			
		||||
242 RPL_STATSUPTIME ":Server Up %d days %d:%02d:%02d"
 | 
			
		||||
251 RPL_LUSERCLIENT ":There are %d users and %d services on %d servers"
 | 
			
		||||
252 RPL_LUSEROP "%d :operator(s) online"
 | 
			
		||||
253 RPL_LUSERUNKNOWN "%d :unknown connection(s)"
 | 
			
		||||
254 RPL_LUSERCHANNELS "%d :channels formed"
 | 
			
		||||
255 RPL_LUSERME ":I have %d clients and %d servers"
 | 
			
		||||
301 RPL_AWAY "%s :%s"
 | 
			
		||||
302 RPL_USERHOST ":%s"
 | 
			
		||||
303 RPL_ISON ":%s"
 | 
			
		||||
305 RPL_UNAWAY ":You are no longer marked as being away"
 | 
			
		||||
306 RPL_NOWAWAY ":You have been marked as being away"
 | 
			
		||||
311 RPL_WHOISUSER "%s %s %s * :%s"
 | 
			
		||||
312 RPL_WHOISSERVER "%s %s :%s"
 | 
			
		||||
313 RPL_WHOISOPERATOR "%s :is an IRC operator"
 | 
			
		||||
314 RPL_WHOWASUSER "%s %s %s * :%s"
 | 
			
		||||
315 RPL_ENDOFWHO "%s :End of WHO list"
 | 
			
		||||
317 RPL_WHOISIDLE "%s %d :seconds idle"
 | 
			
		||||
318 RPL_ENDOFWHOIS "%s :End of WHOIS list"
 | 
			
		||||
319 RPL_WHOISCHANNELS "%s :%s"
 | 
			
		||||
322 RPL_LIST "%s %d :%s"
 | 
			
		||||
323 RPL_LISTEND ":End of LIST"
 | 
			
		||||
324 RPL_CHANNELMODEIS "%s +%s"
 | 
			
		||||
329 RPL_CREATIONTIME "%s %d"
 | 
			
		||||
331 RPL_NOTOPIC "%s :No topic is set"
 | 
			
		||||
332 RPL_TOPIC "%s :%s"
 | 
			
		||||
333 RPL_TOPICWHOTIME "%s %s %d"
 | 
			
		||||
341 RPL_INVITING "%s %s"
 | 
			
		||||
346 RPL_INVITELIST "%s %s"
 | 
			
		||||
347 RPL_ENDOFINVITELIST "%s :End of channel invite list"
 | 
			
		||||
348 RPL_EXCEPTLIST "%s %s"
 | 
			
		||||
349 RPL_ENDOFEXCEPTLIST "%s :End of channel exception list"
 | 
			
		||||
351 RPL_VERSION "%s.%d %s :%s"
 | 
			
		||||
352 RPL_WHOREPLY "%s %s %s %s %s %s :%d %s"
 | 
			
		||||
353 RPL_NAMREPLY "%c %s :%s"
 | 
			
		||||
364 RPL_LINKS "%s %s :%d %s"
 | 
			
		||||
365 RPL_ENDOFLINKS "%s :End of LINKS list"
 | 
			
		||||
366 RPL_ENDOFNAMES "%s :End of NAMES list"
 | 
			
		||||
367 RPL_BANLIST "%s %s"
 | 
			
		||||
368 RPL_ENDOFBANLIST "%s :End of channel ban list"
 | 
			
		||||
369 RPL_ENDOFWHOWAS "%s :End of WHOWAS"
 | 
			
		||||
372 RPL_MOTD ":- %s"
 | 
			
		||||
375 RPL_MOTDSTART ":- %s Message of the day - "
 | 
			
		||||
376 RPL_ENDOFMOTD ":End of MOTD command"
 | 
			
		||||
391 RPL_TIME "%s :%s"
 | 
			
		||||
401 ERR_NOSUCHNICK "%s :No such nick/channel"
 | 
			
		||||
402 ERR_NOSUCHSERVER "%s :No such server"
 | 
			
		||||
403 ERR_NOSUCHCHANNEL "%s :No such channel"
 | 
			
		||||
404 ERR_CANNOTSENDTOCHAN "%s :Cannot send to channel"
 | 
			
		||||
406 ERR_WASNOSUCHNICK "%s :There was no such nickname"
 | 
			
		||||
409 ERR_NOORIGIN ":No origin specified"
 | 
			
		||||
410 ERR_INVALIDCAPCMD "%s :%s"
 | 
			
		||||
411 ERR_NORECIPIENT ":No recipient given (%s)"
 | 
			
		||||
412 ERR_NOTEXTTOSEND ":No text to send"
 | 
			
		||||
421 ERR_UNKNOWNCOMMAND "%s: Unknown command"
 | 
			
		||||
422 ERR_NOMOTD ":MOTD File is missing"
 | 
			
		||||
423 ERR_NOADMININFO "%s :No administrative info available"
 | 
			
		||||
431 ERR_NONICKNAMEGIVEN ":No nickname given"
 | 
			
		||||
432 ERR_ERRONEOUSNICKNAME "%s :Erroneous nickname"
 | 
			
		||||
433 ERR_NICKNAMEINUSE "%s :Nickname is already in use"
 | 
			
		||||
441 ERR_USERNOTINCHANNEL "%s %s :They aren't on that channel"
 | 
			
		||||
442 ERR_NOTONCHANNEL "%s :You're not on that channel"
 | 
			
		||||
443 ERR_USERONCHANNEL "%s %s :is already on channel"
 | 
			
		||||
445 ERR_SUMMONDISABLED ":SUMMON has been disabled"
 | 
			
		||||
446 ERR_USERSDISABLED ":USERS has been disabled"
 | 
			
		||||
451 ERR_NOTREGISTERED ":You have not registered"
 | 
			
		||||
461 ERR_NEEDMOREPARAMS "%s :Not enough parameters"
 | 
			
		||||
462 ERR_ALREADYREGISTERED ":Unauthorized command (already registered)"
 | 
			
		||||
467 ERR_KEYSET "%s :Channel key already set"
 | 
			
		||||
471 ERR_CHANNELISFULL "%s :Cannot join channel (+l)"
 | 
			
		||||
472 ERR_UNKNOWNMODE "%c :is unknown mode char to me for %s"
 | 
			
		||||
473 ERR_INVITEONLYCHAN "%s :Cannot join channel (+i)"
 | 
			
		||||
474 ERR_BANNEDFROMCHAN "%s :Cannot join channel (+b)"
 | 
			
		||||
475 ERR_BADCHANNELKEY "%s :Cannot join channel (+k)"
 | 
			
		||||
476 ERR_BADCHANMASK "%s :Bad Channel Mask"
 | 
			
		||||
481 ERR_NOPRIVILEGES ":Permission Denied- You're not an IRC operator"
 | 
			
		||||
482 ERR_CHANOPRIVSNEEDED "%s :You're not channel operator"
 | 
			
		||||
501 ERR_UMODEUNKNOWNFLAG ":Unknown MODE flag"
 | 
			
		||||
502 ERR_USERSDONTMATCH ":Cannot change mode for other users"
 | 
			
		||||
							
								
								
									
										3461
									
								
								hid/main.go
									
									
									
									
									
								
							
							
						
						
									
										3461
									
								
								hid/main.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										168
									
								
								hid/main_test.go
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								hid/main_test.go
									
									
									
									
									
								
							@@ -1,168 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2015 - 2018, Přemysl Eric Janouch <p@janouch.name>
 | 
			
		||||
//
 | 
			
		||||
// Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
// purpose with or without fee is hereby granted.
 | 
			
		||||
//
 | 
			
		||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 | 
			
		||||
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 | 
			
		||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestSplitString(t *testing.T) {
 | 
			
		||||
	var splitStringTests = []struct {
 | 
			
		||||
		s, delims   string
 | 
			
		||||
		ignoreEmpty bool
 | 
			
		||||
		result      []string
 | 
			
		||||
	}{
 | 
			
		||||
		{",a,,bc", ",", false, []string{"", "a", "", "bc"}},
 | 
			
		||||
		{",a,,bc", ",", true, []string{"a", "bc"}},
 | 
			
		||||
		{"a,;bc,", ",;", false, []string{"a", "", "bc", ""}},
 | 
			
		||||
		{"a,;bc,", ",;", true, []string{"a", "bc"}},
 | 
			
		||||
		{"", ",", false, []string{""}},
 | 
			
		||||
		{"", ",", true, nil},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, d := range splitStringTests {
 | 
			
		||||
		got := splitString(d.s, d.delims, d.ignoreEmpty)
 | 
			
		||||
		if !reflect.DeepEqual(got, d.result) {
 | 
			
		||||
			t.Errorf("case %d: %v should be %v\n", i, got, d.result)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func socketpair() (*os.File, *os.File, error) {
 | 
			
		||||
	pair, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// See go #24331, this makes 1.11 use the internal poller
 | 
			
		||||
	// while there wasn't a way to achieve that before.
 | 
			
		||||
	if err := syscall.SetNonblock(int(pair[0]), true); err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if err := syscall.SetNonblock(int(pair[1]), true); err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fa := os.NewFile(uintptr(pair[0]), "a")
 | 
			
		||||
	if fa == nil {
 | 
			
		||||
		return nil, nil, os.ErrInvalid
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fb := os.NewFile(uintptr(pair[1]), "b")
 | 
			
		||||
	if fb == nil {
 | 
			
		||||
		fa.Close()
 | 
			
		||||
		return nil, nil, os.ErrInvalid
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fa, fb, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDetectTLS(t *testing.T) {
 | 
			
		||||
	detectTLSFromFunc := func(t *testing.T, writer func(net.Conn)) bool {
 | 
			
		||||
		// net.Pipe doesn't use file descriptors, we need a socketpair.
 | 
			
		||||
		sockA, sockB, err := socketpair()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		defer sockA.Close()
 | 
			
		||||
		defer sockB.Close()
 | 
			
		||||
 | 
			
		||||
		fcB, err := net.FileConn(sockB)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		go writer(fcB)
 | 
			
		||||
 | 
			
		||||
		fcA, err := net.FileConn(sockA)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		sc, err := fcA.(syscall.Conn).SyscallConn()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		return detectTLS(sc)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Run("SSL_2.0", func(t *testing.T) {
 | 
			
		||||
		if !detectTLSFromFunc(t, func(fc net.Conn) {
 | 
			
		||||
			// The obsolete, useless, unsupported SSL 2.0 record format.
 | 
			
		||||
			_, _ = fc.Write([]byte{0x80, 0x01, 0x01})
 | 
			
		||||
		}) {
 | 
			
		||||
			t.Error("could not detect SSL")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("crypto_tls", func(t *testing.T) {
 | 
			
		||||
		if !detectTLSFromFunc(t, func(fc net.Conn) {
 | 
			
		||||
			conn := tls.Client(fc, &tls.Config{InsecureSkipVerify: true})
 | 
			
		||||
			_ = conn.Handshake()
 | 
			
		||||
		}) {
 | 
			
		||||
			t.Error("could not detect TLS")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("text", func(t *testing.T) {
 | 
			
		||||
		if detectTLSFromFunc(t, func(fc net.Conn) {
 | 
			
		||||
			_, _ = fc.Write([]byte("ПРЕВЕД"))
 | 
			
		||||
		}) {
 | 
			
		||||
			t.Error("detected UTF-8 as TLS")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("EOF", func(t *testing.T) {
 | 
			
		||||
		type connCloseWriter interface {
 | 
			
		||||
			net.Conn
 | 
			
		||||
			CloseWrite() error
 | 
			
		||||
		}
 | 
			
		||||
		if detectTLSFromFunc(t, func(fc net.Conn) {
 | 
			
		||||
			_ = fc.(connCloseWriter).CloseWrite()
 | 
			
		||||
		}) {
 | 
			
		||||
			t.Error("detected EOF as TLS")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIRC(t *testing.T) {
 | 
			
		||||
	msg := ircParseMessage(
 | 
			
		||||
		`@first=a\:\s\r\n\\;2nd :srv hi there :good m8 :how are you?`)
 | 
			
		||||
 | 
			
		||||
	if !reflect.DeepEqual(msg.tags, map[string]string{
 | 
			
		||||
		"first": "a; \r\n\\",
 | 
			
		||||
		"2nd":   "",
 | 
			
		||||
	}) {
 | 
			
		||||
		t.Error("tags parsed incorrectly")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if msg.nick != "srv" || msg.user != "" || msg.host != "" {
 | 
			
		||||
		t.Error("server name parsed incorrectly")
 | 
			
		||||
	}
 | 
			
		||||
	if msg.command != "hi" {
 | 
			
		||||
		t.Error("command name parsed incorrectly")
 | 
			
		||||
	}
 | 
			
		||||
	if !reflect.DeepEqual(msg.params,
 | 
			
		||||
		[]string{"there", "good m8 :how are you?"}) {
 | 
			
		||||
		t.Error("params parsed incorrectly")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !ircEqual("[fag]^", "{FAG}~") {
 | 
			
		||||
		t.Error("string case comparison not according to RFC 2812")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: More tests.
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								hswc/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								hswc/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	long           = regexp.MustCompile(`(.{72}\S*)\s+`)
 | 
			
		||||
	file, requests *os.File
 | 
			
		||||
	m              sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func wrap(s string) string {
 | 
			
		||||
	return strings.ReplaceAll(long.ReplaceAllString(
 | 
			
		||||
		strings.ReplaceAll(s, "\r", ""), "$1\n"), "\n", "\n ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
	if err := r.ParseForm(); err != nil {
 | 
			
		||||
		w.WriteHeader(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	text := r.FormValue("text")
 | 
			
		||||
	if len(text) > 64<<10 {
 | 
			
		||||
		w.WriteHeader(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.Lock()
 | 
			
		||||
	defer m.Unlock()
 | 
			
		||||
 | 
			
		||||
	j, _ := json.Marshal(struct {
 | 
			
		||||
		URI     string
 | 
			
		||||
		Headers http.Header
 | 
			
		||||
		Form    url.Values
 | 
			
		||||
	}{
 | 
			
		||||
		URI:     r.RequestURI,
 | 
			
		||||
		Headers: r.Header,
 | 
			
		||||
		Form:    r.Form,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if s, err := file.Stat(); err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	} else if s.Size()+int64(len(text)) > 64<<20 {
 | 
			
		||||
		w.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
	} else if r.Form.Has("submit") {
 | 
			
		||||
		// <input type="submit"> should not be named, and thus received.
 | 
			
		||||
		//
 | 
			
		||||
		// If this is not enough to filter out most spammers, consider also:
 | 
			
		||||
		//  - Header: "Origin" should not be missing for POST.
 | 
			
		||||
		//  - Header: "Accept" should not be "*/*".
 | 
			
		||||
		//  - Header: "Accept-Language" and "Accept-Encoding" should be present.
 | 
			
		||||
		//  - Form: _charset_ should not be kept verbatim,
 | 
			
		||||
		//    seeing as Safari/Chromium/Firefox all pass UTF-8,
 | 
			
		||||
		//    in accordance with HTML5.
 | 
			
		||||
		w.WriteHeader(http.StatusTeapot)
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Fprintf(file, "%s %s\n %s\n",
 | 
			
		||||
			time.Now().Local().Format(time.RFC1123), r.RequestURI, wrap(text))
 | 
			
		||||
		if err := file.Sync(); err != nil {
 | 
			
		||||
			log.Fatalln(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// To help filter out spammers.
 | 
			
		||||
		fmt.Fprintf(requests, "%s\n", j)
 | 
			
		||||
		if err := requests.Sync(); err != nil {
 | 
			
		||||
			log.Fatalln(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Fprintln(w, "Saved.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	if len(os.Args) != 3 {
 | 
			
		||||
		log.Fatalf("Usage: %s BIND DB\n", os.Args[0])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	if file, err = os.OpenFile(os.Args[2],
 | 
			
		||||
		os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644); err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
	if requests, err = os.OpenFile(os.Args[2]+".requests",
 | 
			
		||||
		os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644); err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	http.HandleFunc("/", handler)
 | 
			
		||||
	log.Fatalln(http.ListenAndServe(os.Args[1], nil))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								hswg/README.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								hswg/README.adoc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
hswg: a static website generator
 | 
			
		||||
================================
 | 
			
		||||
 | 
			
		||||
hswg wraps libasciidoc to make it understand more syntax, namely
 | 
			
		||||
two-line/underlined titles, and can be run either as a filter, or as a simple
 | 
			
		||||
wiki-like site generator.
 | 
			
		||||
 | 
			
		||||
Gitea/cgit AsciiDoc processor
 | 
			
		||||
-----------------------------
 | 
			
		||||
Wrap hswg in the following script to give it a few superpowers:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# Make this also work for cgit which, strangely enough, is willing to render
 | 
			
		||||
# /anything/ via the /about route, only passing through image/* unchanged.
 | 
			
		||||
if [ -z "$GITEA_PREFIX_SRC" ]; then
 | 
			
		||||
    test "${1%.adoc}" != "$1" || exit 1
 | 
			
		||||
    cgit_fixups='s/<div class="content">/<div>/'
 | 
			
		||||
    export GITEA_PREFIX_SRC=. GITEA_PREFIX_RAW=.
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# libasciidoc can't be helped in other ways so far, adding support for:
 | 
			
		||||
#  - the original 'italics' syntax
 | 
			
		||||
#  - double-line headings (part of haven's hswg which invokes libasciidoc)
 | 
			
		||||
#  - make links to other documents work, normally an attribute could be used
 | 
			
		||||
perl -pe "s|'([-~/\\.\\w]+)'|_\$1_|g;" | hswg 2>/dev/null | \
 | 
			
		||||
    perl -pe 's|(href=")([^/][^:]*?")|$1$ENV{GITEA_PREFIX_SRC}/$2|;' \
 | 
			
		||||
        -e 's|(src=")([^/][^:]*?")|$1$ENV{GITEA_PREFIX_RAW}/$2|;' \
 | 
			
		||||
        -e "$cgit_fixups"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then, to set it up in Gitea, include the following snippet in your _app.ini_:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[markup.asciidoc]
 | 
			
		||||
ENABLED         = true
 | 
			
		||||
FILE_EXTENSIONS = .adoc,.asciidoc
 | 
			
		||||
RENDER_COMMAND  = /usr/local/bin/hswg-gitea
 | 
			
		||||
IS_INPUT_FILE   = false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Similarly for cgit, the following _cgitrc_ snippet might do the job:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
about-filter=/usr/local/bin/hswg-gitea
 | 
			
		||||
readme=:README.adoc
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If parsing fails for some reason, the contents will be wrapped in HTML verbatim
 | 
			
		||||
as plain text.
 | 
			
		||||
 | 
			
		||||
Wiki mode
 | 
			
		||||
---------
 | 
			
		||||
The program will read a Go template for the index page from its standard input,
 | 
			
		||||
and another template for rendered pages from the path given as its first
 | 
			
		||||
argument.  The second argument specifies the output filename for the index page,
 | 
			
		||||
and the last one is the document directory.
 | 
			
		||||
 | 
			
		||||
Consult the source code for a list template variables.
 | 
			
		||||
 | 
			
		||||
All pages will be initially rerendered on startup, and then the directory will
 | 
			
		||||
be watched for changes in real time using the inotify API.
 | 
			
		||||
							
								
								
									
										54
									
								
								hswg/asciidoc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								hswg/asciidoc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isTitle returns the title level if the lines seem to form a title,
 | 
			
		||||
// zero otherwise. Input lines may inclide trailing newlines.
 | 
			
		||||
func isTitle(line1, line2 []byte) int {
 | 
			
		||||
	// This is a very naïve method, we should target graphemes (thus at least
 | 
			
		||||
	// NFC normalize the lines first) and account for wide characters.
 | 
			
		||||
	diff := utf8.RuneCount(line1) - utf8.RuneCount(line2)
 | 
			
		||||
	if len(line2) < 2 || diff < -1 || diff > 1 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// "Don't be fooled by back-to-back delimited blocks."
 | 
			
		||||
	// Still gets fooled by other things, though.
 | 
			
		||||
	if bytes.IndexFunc(line1, func(r rune) bool {
 | 
			
		||||
		return unicode.IsLetter(r) || unicode.IsNumber(r)
 | 
			
		||||
	}) < 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The underline must be homogenous.
 | 
			
		||||
	for _, r := range bytes.TrimRight(line2, "\r\n") {
 | 
			
		||||
		if r != line2[0] {
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 1 + strings.IndexByte("=-~^+", line2[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeLine(w *io.PipeWriter, cur, next []byte) []byte {
 | 
			
		||||
	if level := isTitle(cur, next); level > 0 {
 | 
			
		||||
		w.Write(append(bytes.Repeat([]byte{'='}, level), ' '))
 | 
			
		||||
		next = nil
 | 
			
		||||
	}
 | 
			
		||||
	w.Write(cur)
 | 
			
		||||
	return next
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertTitles converts AsciiDoc two-line (underlined) titles to single-line.
 | 
			
		||||
func ConvertTitles(w *io.PipeWriter, input []byte) {
 | 
			
		||||
	var last []byte
 | 
			
		||||
	for _, cur := range bytes.SplitAfter(input, []byte{'\n'}) {
 | 
			
		||||
		last = writeLine(w, last, cur)
 | 
			
		||||
	}
 | 
			
		||||
	writeLine(w, last, nil)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										139
									
								
								hswg/main.go
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								hswg/main.go
									
									
									
									
									
								
							@@ -17,64 +17,17 @@ import (
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unicode"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"github.com/bytesparadise/libasciidoc/pkg/configuration"
 | 
			
		||||
	"github.com/bytesparadise/libasciidoc/pkg/parser"
 | 
			
		||||
	"github.com/bytesparadise/libasciidoc/pkg/renderer"
 | 
			
		||||
	"github.com/bytesparadise/libasciidoc/pkg/renderer/sgml/html5"
 | 
			
		||||
	"github.com/bytesparadise/libasciidoc/pkg/types"
 | 
			
		||||
	"github.com/bytesparadise/libasciidoc/pkg/validator"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isTitle returns the title level if the lines seem to form a title,
 | 
			
		||||
// zero otherwise. Input lines may inclide trailing newlines.
 | 
			
		||||
func isTitle(line1, line2 []byte) int {
 | 
			
		||||
	// This is a very naïve method, we should target graphemes (thus at least
 | 
			
		||||
	// NFC normalize the lines first) and account for wide characters.
 | 
			
		||||
	diff := utf8.RuneCount(line1) - utf8.RuneCount(line2)
 | 
			
		||||
	if len(line2) < 2 || diff < -1 || diff > 1 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// "Don't be fooled by back-to-back delimited blocks."
 | 
			
		||||
	// Still gets fooled by other things, though.
 | 
			
		||||
	if bytes.IndexFunc(line1, func(r rune) bool {
 | 
			
		||||
		return unicode.IsLetter(r) || unicode.IsNumber(r)
 | 
			
		||||
	}) < 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The underline must be homogenous.
 | 
			
		||||
	for _, r := range bytes.TrimRight(line2, "\r\n") {
 | 
			
		||||
		if r != line2[0] {
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 1 + strings.IndexByte("=-~^+", line2[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeLine(w *io.PipeWriter, cur, next []byte) []byte {
 | 
			
		||||
	if level := isTitle(cur, next); level > 0 {
 | 
			
		||||
		w.Write(append(bytes.Repeat([]byte{'='}, level), ' '))
 | 
			
		||||
		next = nil
 | 
			
		||||
	}
 | 
			
		||||
	w.Write(cur)
 | 
			
		||||
	return next
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertTitles converts AsciiDoc two-line (underlined) titles to single-line.
 | 
			
		||||
func ConvertTitles(w *io.PipeWriter, input []byte) {
 | 
			
		||||
	var last []byte
 | 
			
		||||
	for _, cur := range bytes.SplitAfter(input, []byte{'\n'}) {
 | 
			
		||||
		last = writeLine(w, last, cur)
 | 
			
		||||
	}
 | 
			
		||||
	writeLine(w, last, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Metadata contains select metadata about a rendered document.
 | 
			
		||||
type Metadata struct {
 | 
			
		||||
	types.Metadata
 | 
			
		||||
@@ -88,9 +41,28 @@ type Metadata struct {
 | 
			
		||||
// be linked anywhere else.
 | 
			
		||||
func (m *Metadata) IsDraft() bool { return m.Attributes.Has("draft") }
 | 
			
		||||
 | 
			
		||||
// Attr is a shortcut for retrieving document attributes by name.
 | 
			
		||||
func (m *Metadata) Attr(name string) string {
 | 
			
		||||
	return m.Attributes.GetAsStringWithDefault(name, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttrList is similar to Attr, but splits the result at commas,
 | 
			
		||||
// and trims whitespace around array elements.
 | 
			
		||||
func (m *Metadata) AttrList(name string) []string {
 | 
			
		||||
	if !m.Attributes.Has(name) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res := strings.Split(m.Attr(name), ",")
 | 
			
		||||
	for i := range res {
 | 
			
		||||
		res[i] = strings.TrimSpace(res[i])
 | 
			
		||||
	}
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Render converts an io.Reader with an AsciiDoc document to HTML. So long as
 | 
			
		||||
// the file could be read at all, it will always return a non-empty document.
 | 
			
		||||
func Render(r io.Reader, config configuration.Configuration) (
 | 
			
		||||
func Render(r io.Reader, config *configuration.Configuration) (
 | 
			
		||||
	html *bytes.Buffer, meta Metadata, err error) {
 | 
			
		||||
	html = bytes.NewBuffer(nil)
 | 
			
		||||
 | 
			
		||||
@@ -108,17 +80,18 @@ func Render(r io.Reader, config configuration.Configuration) (
 | 
			
		||||
	// io.Copy(os.Stdout, pr)
 | 
			
		||||
	// return
 | 
			
		||||
 | 
			
		||||
	var doc types.Document
 | 
			
		||||
	var doc *types.Document
 | 
			
		||||
	if doc, err = parser.ParseDocument(pr, config); err == nil {
 | 
			
		||||
		problems, err := validator.Validate(&doc)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintln(os.Stderr, err)
 | 
			
		||||
		doctype := config.Attributes.GetAsStringWithDefault(
 | 
			
		||||
			types.AttrDocType, "article")
 | 
			
		||||
		problems, verr := validator.Validate(doc, doctype)
 | 
			
		||||
		if verr != nil {
 | 
			
		||||
			fmt.Fprintln(os.Stderr, verr)
 | 
			
		||||
		}
 | 
			
		||||
		for _, problem := range problems {
 | 
			
		||||
			fmt.Fprintln(os.Stderr, problem.Message)
 | 
			
		||||
		}
 | 
			
		||||
		ctx := renderer.NewContext(doc, config)
 | 
			
		||||
		meta.Metadata, err = html5.Render(ctx, doc, html)
 | 
			
		||||
		meta.Metadata, err = html5.Render(doc, config, html)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Fallback: output all the text sanitized for direct inclusion.
 | 
			
		||||
@@ -131,7 +104,7 @@ func Render(r io.Reader, config configuration.Configuration) (
 | 
			
		||||
		}
 | 
			
		||||
		_, _ = html.WriteString("</pre>")
 | 
			
		||||
	}
 | 
			
		||||
	meta.Attributes = doc.Attributes
 | 
			
		||||
	meta.Attributes = config.Attributes
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -149,13 +122,14 @@ type Entry struct {
 | 
			
		||||
 | 
			
		||||
// Published returns the date when the entry was published, or nil if unknown.
 | 
			
		||||
func (e *Entry) Published() *time.Time {
 | 
			
		||||
	if d, _, err := e.Attributes.GetAsString("date"); err != nil {
 | 
			
		||||
	if d, ok := e.Attributes.GetAsString("date"); !ok {
 | 
			
		||||
		return nil
 | 
			
		||||
	} else if t, err := time.Parse(time.RFC3339, d); err == nil {
 | 
			
		||||
		return &t
 | 
			
		||||
	} else if t, err := time.Parse("2006-01-02", d); err == nil {
 | 
			
		||||
		return &t
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf("%s: date: %s\n", e.PathSource, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -217,6 +191,9 @@ func renderEntry(name string, e *Entry) error {
 | 
			
		||||
	if html, e.Metadata, err = Render(f, configuration.NewConfiguration(
 | 
			
		||||
		configuration.WithFilename(e.PathSource),
 | 
			
		||||
		configuration.WithLastUpdated(e.mtime),
 | 
			
		||||
		configuration.WithAttribute("toc", "preamble"),
 | 
			
		||||
		configuration.WithAttribute("toc-title", "<h2>Contents</h2>"),
 | 
			
		||||
		configuration.WithAttribute("source-highlighter", "chroma"),
 | 
			
		||||
	)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -314,14 +291,25 @@ func writeIndex(path string, t *template.Template,
 | 
			
		||||
 | 
			
		||||
func finalizeEntries(entries *map[string]*Entry, t *template.Template,
 | 
			
		||||
	indexPath string, indexT *template.Template) {
 | 
			
		||||
	// The initial render of a large amount of entries is resource-intensive.
 | 
			
		||||
	var wg sync.WaitGroup
 | 
			
		||||
	for name, e := range *entries {
 | 
			
		||||
		e.backlinks = map[string]bool{}
 | 
			
		||||
		if e.raw == nil {
 | 
			
		||||
		if e.raw != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wg.Add(1)
 | 
			
		||||
		go func(name string, e *Entry) {
 | 
			
		||||
			defer wg.Done()
 | 
			
		||||
			if err := renderEntry(name, e); err != nil {
 | 
			
		||||
				log.Printf("%s: %s\n", name, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		}(name, e)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wg.Wait()
 | 
			
		||||
 | 
			
		||||
	for name, e := range *entries {
 | 
			
		||||
		// Expand LinkWords anywhere between <tags>.
 | 
			
		||||
		// We want something like the inverse of Regexp.ReplaceAllStringFunc.
 | 
			
		||||
@@ -366,6 +354,15 @@ func dispatchEvents(dirname string, r io.Reader, ch chan<- *watchEvent) error {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		base := make([]byte, e.Len)
 | 
			
		||||
		if e.Len != 0 {
 | 
			
		||||
			if n, err := r.Read(base); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			} else if n < int(e.Len) {
 | 
			
		||||
				return fmt.Errorf("short read")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case e.Mask&syscall.IN_IGNORED != 0:
 | 
			
		||||
			return fmt.Errorf("watch removed by kernel")
 | 
			
		||||
@@ -377,13 +374,6 @@ func dispatchEvents(dirname string, r io.Reader, ch chan<- *watchEvent) error {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		base := make([]byte, e.Len)
 | 
			
		||||
		if n, err := r.Read(base); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		} else if n < int(e.Len) {
 | 
			
		||||
			return fmt.Errorf("short read")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		basename, interesting := string(base[:bytes.IndexByte(base, 0)]), false
 | 
			
		||||
		for _, glob := range globs {
 | 
			
		||||
			if matches, _ := filepath.Match(glob, basename); matches {
 | 
			
		||||
@@ -446,6 +436,17 @@ func watchDirectory(dirname string) (<-chan *watchEvent, error) {
 | 
			
		||||
	return ch, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var funcs = template.FuncMap{
 | 
			
		||||
	"contains": func(needle string, haystack []string) bool {
 | 
			
		||||
		for _, el := range haystack {
 | 
			
		||||
			if el == needle {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func singleFile() {
 | 
			
		||||
	html, meta, err := Render(os.Stdin, configuration.NewConfiguration())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -474,7 +475,7 @@ func main() {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
	tmplEntry, err := template.New("entry").Parse(string(header))
 | 
			
		||||
	tmplEntry, err := template.New("entry").Funcs(funcs).Parse(string(header))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -484,7 +485,7 @@ func main() {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
	tmplIndex, err := template.New("index").Parse(string(index))
 | 
			
		||||
	tmplIndex, err := template.New("index").Funcs(funcs).Parse(string(index))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -496,7 +497,7 @@ func main() {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signals := make(chan os.Signal)
 | 
			
		||||
	signals := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(signals, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM)
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,17 +2,19 @@ package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"github.com/BurntSushi/xgb"
 | 
			
		||||
	"github.com/BurntSushi/xgb/render"
 | 
			
		||||
	"github.com/BurntSushi/xgb/shm"
 | 
			
		||||
	"github.com/BurntSushi/xgb/xproto"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/BurntSushi/xgb"
 | 
			
		||||
	"github.com/BurntSushi/xgb/render"
 | 
			
		||||
	"github.com/BurntSushi/xgb/shm"
 | 
			
		||||
	"github.com/BurntSushi/xgb/xproto"
 | 
			
		||||
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	_ "image/gif"
 | 
			
		||||
	_ "image/jpeg"
 | 
			
		||||
	_ "image/png"
 | 
			
		||||
@@ -25,6 +27,47 @@ import "C"
 | 
			
		||||
func F64ToFixed(f float64) render.Fixed { return render.Fixed(f * 65536) }
 | 
			
		||||
func FixedToF64(f render.Fixed) float64 { return float64(f) / 65536 }
 | 
			
		||||
 | 
			
		||||
var formats = map[byte]struct {
 | 
			
		||||
	format    render.Directformat
 | 
			
		||||
	transform func(color.Color) uint32
 | 
			
		||||
}{
 | 
			
		||||
	32: {
 | 
			
		||||
		format: render.Directformat{
 | 
			
		||||
			RedShift:   16,
 | 
			
		||||
			RedMask:    0xff,
 | 
			
		||||
			GreenShift: 8,
 | 
			
		||||
			GreenMask:  0xff,
 | 
			
		||||
			BlueShift:  0,
 | 
			
		||||
			BlueMask:   0xff,
 | 
			
		||||
			AlphaShift: 24,
 | 
			
		||||
			AlphaMask:  0xff,
 | 
			
		||||
		},
 | 
			
		||||
		transform: func(color color.Color) uint32 {
 | 
			
		||||
			r, g, b, a := color.RGBA()
 | 
			
		||||
			return (a>>8)<<24 | (r>>8)<<16 | (g>>8)<<8 | (b >> 8)
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	30: {
 | 
			
		||||
		/*
 | 
			
		||||
			// Alpha makes compositing unbearably slow.
 | 
			
		||||
			AlphaShift: 30,
 | 
			
		||||
			AlphaMask:  0x3,
 | 
			
		||||
		*/
 | 
			
		||||
		format: render.Directformat{
 | 
			
		||||
			RedShift:   20,
 | 
			
		||||
			RedMask:    0x3ff,
 | 
			
		||||
			GreenShift: 10,
 | 
			
		||||
			GreenMask:  0x3ff,
 | 
			
		||||
			BlueShift:  0,
 | 
			
		||||
			BlueMask:   0x3ff,
 | 
			
		||||
		},
 | 
			
		||||
		transform: func(color color.Color) uint32 {
 | 
			
		||||
			r, g, b, a := color.RGBA()
 | 
			
		||||
			return (a>>14)<<30 | (r>>6)<<20 | (g>>6)<<10 | (b >> 6)
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	/*
 | 
			
		||||
		pf, err := os.Create("pprof.out")
 | 
			
		||||
@@ -62,18 +105,37 @@ func main() {
 | 
			
		||||
	screen := setup.DefaultScreen(X)
 | 
			
		||||
 | 
			
		||||
	visual, depth := screen.RootVisual, screen.RootDepth
 | 
			
		||||
	// TODO: We should check that we find it, though we don't /need/ alpha here,
 | 
			
		||||
	// it's just a minor improvement--affects the backpixel value.
 | 
			
		||||
 | 
			
		||||
	// Only go for 10-bit when the picture can make use of that range.
 | 
			
		||||
	prefer30 := false
 | 
			
		||||
	switch img.(type) {
 | 
			
		||||
	case *image.Gray16, *image.RGBA64, *image.NRGBA64:
 | 
			
		||||
		prefer30 = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// XXX: We don't /need/ alpha here, it's just a minor improvement--affects
 | 
			
		||||
	// the backpixel value. (And we reject it in 30-bit depth anyway.)
 | 
			
		||||
Depths:
 | 
			
		||||
	for _, i := range screen.AllowedDepths {
 | 
			
		||||
		for _, v := range i.Visuals {
 | 
			
		||||
			// TODO: Could/should check other parameters.
 | 
			
		||||
			if i.Depth == 32 && v.Class == xproto.VisualClassTrueColor {
 | 
			
		||||
			// TODO: Could/should check other parameters, e.g., the RGB masks.
 | 
			
		||||
			if v.Class != xproto.VisualClassTrueColor {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if i.Depth == 32 || i.Depth == 30 && prefer30 {
 | 
			
		||||
				visual, depth = v.VisualId, i.Depth
 | 
			
		||||
				break
 | 
			
		||||
				if !prefer30 || i.Depth == 30 {
 | 
			
		||||
					break Depths
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	format, ok := formats[depth]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		log.Fatalln("unsupported bit depth")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mid, err := xproto.NewColormapId(X)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
@@ -91,7 +153,7 @@ func main() {
 | 
			
		||||
	_ = xproto.CreateWindow(X, depth, wid, screen.Root,
 | 
			
		||||
		0, 0, 500, 500, 0, xproto.WindowClassInputOutput,
 | 
			
		||||
		visual, xproto.CwBackPixel|xproto.CwBorderPixel|xproto.CwEventMask|
 | 
			
		||||
			xproto.CwColormap, []uint32{0x80808080, 0,
 | 
			
		||||
			xproto.CwColormap, []uint32{format.transform(color.Alpha{0x80}), 0,
 | 
			
		||||
			xproto.EventMaskStructureNotify | xproto.EventMaskExposure,
 | 
			
		||||
			uint32(mid)})
 | 
			
		||||
 | 
			
		||||
@@ -131,7 +193,7 @@ func main() {
 | 
			
		||||
	// setup.BitmapFormatScanline{Pad,Unit} and setup.BitmapFormatBitOrder
 | 
			
		||||
	// don't interest us here since we're only using Z format pixmaps.
 | 
			
		||||
	for _, pf := range setup.PixmapFormats {
 | 
			
		||||
		if pf.Depth == 32 {
 | 
			
		||||
		if pf.Depth == depth {
 | 
			
		||||
			if pf.BitsPerPixel != 32 || pf.ScanlinePad != 32 {
 | 
			
		||||
				log.Fatalln("unsuported X server")
 | 
			
		||||
			}
 | 
			
		||||
@@ -142,28 +204,18 @@ func main() {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
	_ = xproto.CreatePixmap(X, 32, pixid, xproto.Drawable(screen.Root),
 | 
			
		||||
	_ = xproto.CreatePixmap(X, depth, pixid, xproto.Drawable(screen.Root),
 | 
			
		||||
		uint16(img.Bounds().Dx()), uint16(img.Bounds().Dy()))
 | 
			
		||||
 | 
			
		||||
	var bgraFormat render.Pictformat
 | 
			
		||||
	wanted := render.Directformat{
 | 
			
		||||
		RedShift:   16,
 | 
			
		||||
		RedMask:    0xff,
 | 
			
		||||
		GreenShift: 8,
 | 
			
		||||
		GreenMask:  0xff,
 | 
			
		||||
		BlueShift:  0,
 | 
			
		||||
		BlueMask:   0xff,
 | 
			
		||||
		AlphaShift: 24,
 | 
			
		||||
		AlphaMask:  0xff,
 | 
			
		||||
	}
 | 
			
		||||
	for _, pf := range pformats.Formats {
 | 
			
		||||
		if pf.Depth == 32 && pf.Direct == wanted {
 | 
			
		||||
		if pf.Depth == depth && pf.Direct == format.format {
 | 
			
		||||
			bgraFormat = pf.Id
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if bgraFormat == 0 {
 | 
			
		||||
		log.Fatalln("ARGB format not found")
 | 
			
		||||
		log.Fatalln("picture format not found")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We could also look for the inverse pictformat.
 | 
			
		||||
@@ -201,14 +253,12 @@ func main() {
 | 
			
		||||
		row := make([]byte, bounds.Dx()*4)
 | 
			
		||||
		for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
 | 
			
		||||
			for x := bounds.Min.X; x < bounds.Max.X; x++ {
 | 
			
		||||
				r, g, b, a := img.At(x, y).RGBA()
 | 
			
		||||
				encoding.PutUint32(row[x*4:],
 | 
			
		||||
					(a>>8)<<24|(r>>8)<<16|(g>>8)<<8|(b>>8))
 | 
			
		||||
				encoding.PutUint32(row[x*4:], format.transform(img.At(x, y)))
 | 
			
		||||
			}
 | 
			
		||||
			_ = xproto.PutImage(X, xproto.ImageFormatZPixmap,
 | 
			
		||||
				xproto.Drawable(pixid), cid, uint16(bounds.Dx()), 1,
 | 
			
		||||
				0, int16(y),
 | 
			
		||||
				0, 32, row)
 | 
			
		||||
				0, depth, row)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		rep, err := shm.QueryVersion(X).Reply()
 | 
			
		||||
@@ -241,9 +291,7 @@ func main() {
 | 
			
		||||
		for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
 | 
			
		||||
			row := data[y*bounds.Dx()*4:]
 | 
			
		||||
			for x := bounds.Min.X; x < bounds.Max.X; x++ {
 | 
			
		||||
				r, g, b, a := img.At(x, y).RGBA()
 | 
			
		||||
				encoding.PutUint32(row[x*4:],
 | 
			
		||||
					(a>>8)<<24|(r>>8)<<16|(g>>8)<<8|(b>>8))
 | 
			
		||||
				encoding.PutUint32(row[x*4:], format.transform(img.At(x, y)))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -261,7 +309,7 @@ func main() {
 | 
			
		||||
		_ = shm.PutImage(X, xproto.Drawable(pixid), cid,
 | 
			
		||||
			uint16(bounds.Dx()), uint16(bounds.Dy()), 0, 0,
 | 
			
		||||
			uint16(bounds.Dx()), uint16(bounds.Dy()), 0, 0,
 | 
			
		||||
			32, xproto.ImageFormatZPixmap,
 | 
			
		||||
			depth, xproto.ImageFormatZPixmap,
 | 
			
		||||
			0 /* SendEvent */, segid, 0 /* Offset */)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user