Compare commits
55 Commits
056391eeca
...
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
|
|||
|
04e19f5186
|
|||
|
49a685c32e
|
|||
|
d763ce619d
|
|||
|
8276f6bcb9
|
|||
|
dd5c583e8b
|
|||
|
63d18d068d
|
|||
|
d47a8d2237
|
|||
|
a979edf5b7
|
|||
|
9db34a955b
|
|||
|
35974efe21
|
|||
|
8f542c7120
|
|||
|
ea8c59961c
|
|||
|
750f2139f5
|
|||
|
3d002bc540
|
|||
|
084a0a94b0
|
|||
|
91b1120c4a
|
|||
|
f7f892fb59
|
|||
|
d0ce3e3e66
|
|||
|
3a5cc216bb
|
|||
|
a049249d81
|
|||
|
d4eb9cde39
|
|||
|
cb1c8f8563
|
|||
|
13275f1dd3
|
|||
|
030a23c1a2
|
|||
|
0d37e5bc8a
|
|||
|
eae39b13c2
|
|||
|
95f183aa48
|
|||
|
e7ea35f304
|
16
.gitignore
vendored
16
.gitignore
vendored
@@ -1 +1,15 @@
|
||||
/build
|
||||
/hasp/hasp
|
||||
/hid/hid
|
||||
/hnc/hnc
|
||||
/hpcu/hpcu
|
||||
/hswg/hswg
|
||||
/ht/ht
|
||||
/prototypes/tls-autodetect
|
||||
/prototypes/xgb-draw
|
||||
/prototypes/xgb-image
|
||||
/prototypes/xgb-keys
|
||||
/prototypes/xgb-monitors
|
||||
/prototypes/xgb-selection
|
||||
/prototypes/xgb-text-viewer
|
||||
/prototypes/xgb-window
|
||||
/prototypes/xgb-xrender
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018, Přemysl 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.
|
||||
|
||||
294
README
294
README
@@ -1,294 +0,0 @@
|
||||
Project haven
|
||||
=============
|
||||
|
||||
haven is an umbrella project for a range of mostly desktop applications.
|
||||
|
||||
Goal
|
||||
----
|
||||
The greater goal is to create a fresh computing environment for daily work and
|
||||
play--easily controllable, reasonably complex, both visually and internally
|
||||
unified and last but not least responsive. One should be able to use it
|
||||
comfortably with a 60% keyboard and no pointing device.
|
||||
|
||||
haven serves as a testing ground, leaning on the side of compromises. It aims
|
||||
to use today's Linux desktop as a support, relying on X11/Wayland, existing
|
||||
window managers and web browsers.
|
||||
|
||||
The focus is therefore on going breadth-first, not depth-first. Applications
|
||||
only need to be good enough to be able to replace their older siblings at all.
|
||||
I.e. for me personally.
|
||||
|
||||
Scope
|
||||
-----
|
||||
Subproject names aim to have the minimum viable, reasonably identifiable name.
|
||||
To group them together, a common prefix of "h" is used. The second column is
|
||||
what should be used as the name in .desktop files, just like the GNOME project
|
||||
figured out it would make sense:
|
||||
|
||||
- hbe - bitmap editor
|
||||
- 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
|
||||
- hss - spreadsheets
|
||||
- htd - translation dictionary
|
||||
- ht - terminal emulator
|
||||
- htk - GUI toolkit library
|
||||
|
||||
See Projects for more information about the individual projects.
|
||||
|
||||
Some taken names in Debian: hd (important), hte, hy.
|
||||
|
||||
Identity
|
||||
--------
|
||||
The name merely hints at motivations and otherwise isn't of any practical
|
||||
significance other than that we need an identifier. This time I resisted using
|
||||
something offensive for personal amusement.
|
||||
|
||||
A logo covering the entire project is not needed and it seems hard to figure out
|
||||
anything meaninful anyway, though we might pick a specific font to use for the
|
||||
project name <1>.
|
||||
|
||||
The only mascot I can think of would be a black and white or generally grayscale
|
||||
My Little Pony OC but I don't really want to bring my own kinks into the project
|
||||
and I'd also need to learn how to draw one so that I don't infringe on someone
|
||||
else's copyright, or find someone else to do it. Anyway, in lack of a proper
|
||||
logo, she could have a simple "h" or "hvn" for a cutie mark <2>.
|
||||
|
||||
__
|
||||
<2> _/ /_ <1> | _ _ _ _
|
||||
\ _ \ |/ \ / \| \ / /_\ |/ \
|
||||
/ / / / | | | | \ / | | |
|
||||
/_/ /_/ | | \_/| \/ \_/ | |
|
||||
|
||||
I'm not sure where I took this "h" letter styling from, it seems too familiar.
|
||||
The above illustrations also show how awful it looks when a logo is just
|
||||
a stylized version of the first letter of a name when you put the two next to
|
||||
each other. Distinctly redundant. Facebook and Twitter are doing fine, though,
|
||||
perhaps because they do not use them together like that.
|
||||
|
||||
Technicalities
|
||||
--------------
|
||||
|
||||
Languages
|
||||
~~~~~~~~~
|
||||
Primarily Golang with limited C interfacing glue, secondarily C++17, mostly for
|
||||
when the former cannot be reasonably used because of dependencies.
|
||||
|
||||
Build system
|
||||
~~~~~~~~~~~~
|
||||
https://github.com/zevv/bucklespring is a good example of a rather simplified
|
||||
project that makes do with a single Makefile, even for cross-compilation on
|
||||
Windows. Let us avoid CMake and the likes of it.
|
||||
|
||||
It seems that Go can link dynamically, therefore I could build libhaven.so
|
||||
(https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ
|
||||
and https://stackoverflow.com/questions/1757090/shared-library-in-go)
|
||||
and have the rest of the package as rather small binaries linking to it.
|
||||
The "cannot implicitly include runtime/cgo in a shared library" error is solved
|
||||
by "go install", which again requires "-pkgdir" because of privileges.
|
||||
libstd.so is a beautiful 30 megabytes (compared to libc.a: 4.9M).
|
||||
|
||||
GUI
|
||||
~~~
|
||||
Probably build on top of X11/Xlib or xgb<1>. Wayland can wait until it
|
||||
stabilizes--it should not be a major issue switching the backends.
|
||||
Vector graphics can be handled by draw2d<2>.
|
||||
|
||||
<1> https://rosettacode.org/wiki/Window_creation/X11#Go
|
||||
<2> https://github.com/llgcode/draw2d
|
||||
|
||||
The c2 wiki unsurprisingly has a lot of material around the design and
|
||||
realisation of GUIs, which might be useful.
|
||||
|
||||
It seems like an aligning/constraint-based "layout manager" will be one of the
|
||||
first harder problems here. However I certainly don't want to use fixed
|
||||
coordinates as they would introduce problems with different fonts and i18n.
|
||||
|
||||
We could use BDF fonts from the X11 distribution, but draw2d has native support
|
||||
for FreeType fonts and it's more of a choice between vectors and bitmaps.
|
||||
|
||||
The looks will be heavily inspired by Haiku and Windows 2000 and the user will
|
||||
have no say in this, for simplicity.
|
||||
|
||||
.Resources:
|
||||
- https://github.com/golang/exp/tree/master/shiny is a GUI library
|
||||
- https://github.com/as/shiny is a fork of it
|
||||
- http://man.cat-v.org/plan_9/1/rio has a particular, unusual model
|
||||
|
||||
Internationalisation
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
For i18n https://github.com/leonelquinteros/gotext could be used, however I'll
|
||||
probably give up on this issue as I'm fine enough with English.
|
||||
|
||||
Go also has x/text packages for this purpose, which might be better than GNU,
|
||||
but they're essentially still in development.
|
||||
|
||||
Versioning
|
||||
~~~~~~~~~~
|
||||
Versions are for end users. We can use a zero-based, strictly increasing
|
||||
number, be it a simple sequence or date-based numbers such as 1807. If we do
|
||||
this at all, we will eventually also need to release patch versions.
|
||||
|
||||
Since dates don't seem to convey important information, let us settle on 0, 1,
|
||||
1.1, 2, 3, 3.1, 3.2, ... In practice releases are going to be scarce, unless
|
||||
we find a person to take care of it. Note that there is no major/minor pair--
|
||||
a new project will be created when radical philosophical or architectural
|
||||
changes are to be made. See Goal.
|
||||
|
||||
Projects
|
||||
--------
|
||||
These are sorted in the order in which they should be created in order to gain
|
||||
the best possible momentum. The htk GUI toolkit is implied as a side product
|
||||
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.
|
||||
|
||||
hpcu -- PRIMARY-CLIPBOARD unifier
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
An improved replacement for autocutsel in selection synchronization "mode":
|
||||
|
||||
- using only one OS process;
|
||||
- not polling selections twice a second unnecessarily;
|
||||
- calling SetSelectionOwner on change even when it already owns the selection,
|
||||
so that XFIXES SelectionNotify events are delivered;
|
||||
- not using cut buffers for anything.
|
||||
|
||||
Only UTF8_STRING-convertible selections are synchronized.
|
||||
|
||||
hasp -- (lib)asciidoc syntax preprocessor
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Provisional tool to make libasciidoc understand more syntax, namely
|
||||
two-line/underlined titles for my Gitea projects.
|
||||
|
||||
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
|
||||
variable-width/proportional fonts. Initially done primarily to produce a text
|
||||
editing widget, which is going to be an interesting challenge, arguably better
|
||||
solved by whole program composition. Scintilla may provide some inspiration.
|
||||
|
||||
In the second stage, support for the Language Server Protocol will be added so
|
||||
that the project can be edited using its own tools. Some scripting, perhaps
|
||||
a tiny subset of VimL, might be desirable. Or other means of configuration.
|
||||
|
||||
Visual block mode or the color column may still be implemented.
|
||||
|
||||
The real model for the editor is Qt Creator with FakeVIM, though this is not to
|
||||
be a clone of it, e.g. the various "Output" lists could be just special buffers,
|
||||
which may be have names starting on "// ".
|
||||
|
||||
.Resources:
|
||||
- http://doc.cat-v.org/plan_9/4th_edition/papers/sam/
|
||||
|
||||
ho -- all-powerful organizer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Zettelkasten with fulltext search, arbitrary reciprocal links, arbitrary tags.
|
||||
Flat storage. Should be able to use translation dictionaries for search hints.
|
||||
|
||||
Indexing and search may be based on a common database, no need to get all fancy:
|
||||
|
||||
- http://rachbelaid.com/postgres-full-text-search-is-good-enough/
|
||||
- https://www.sqlite.org/fts3.html#full_text_index_queries (FTS4 seems better)
|
||||
|
||||
htd -- translation dictionary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
This specific kind of application doesn't need a lot of user interface either,
|
||||
just a tab bar, text entry and two columns of text with simple formatting.
|
||||
|
||||
For simplicity we will establish a custom dictionary format based on either
|
||||
simple compress/gzip with separate files in StarDict style or, since we don't
|
||||
really strive for random access and memory-efficiency (those 120M that sdtui
|
||||
takes with my 10 dictionaries isn't particularly bad), pack everything with
|
||||
archive/zip.
|
||||
|
||||
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
|
||||
most basic features includes a VFS for archives. The editing widget in
|
||||
read-only mode could be used for F3. The shell is going to work very simply,
|
||||
creating a PTY device and running things under TERM=dumb while decoding SGR,
|
||||
or one could decide to run a new terminal emulator with a different shortcut.
|
||||
ht could probably also be integrated.
|
||||
|
||||
Eventually the number of panels should be arbitrary with proper shortcuts for
|
||||
working with them. We might also integrate a special view for picture previews,
|
||||
which might or might not deserve its own program.
|
||||
|
||||
hss -- spreadsheets
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
The first version doesn't need to be able to reference other cells, and can more
|
||||
or less be a CSV editor.
|
||||
|
||||
We can take inspiration from Excel:
|
||||
|
||||
- https://docs.microsoft.com/en-us/office/client-developer/excel/excel-recalculation
|
||||
- https://www.microsoft.com/en-us/research/uploads/prod/2018/03/build-systems.pdf
|
||||
|
||||
The rest
|
||||
~~~~~~~~
|
||||
Currently there are no significant, specific plans about the other applications.
|
||||
155
README.adoc
Normal file
155
README.adoc
Normal file
@@ -0,0 +1,155 @@
|
||||
Project haven
|
||||
=============
|
||||
|
||||
haven is an umbrella project for a range of mostly desktop applications.
|
||||
|
||||
This README is being converted into a wiki on the wiki branch, also publicly
|
||||
available at https://p.janouch.name/haven/Haven.html[]. We should only document
|
||||
here that which has been created, as the extent of the rationale and plans is
|
||||
gigantic and seems to have a life of its own.
|
||||
|
||||
Goal
|
||||
----
|
||||
The greater goal is to create a fresh computing environment for daily work and
|
||||
play--easily controllable, reasonably complex, both visually and internally
|
||||
unified and last but not least responsive. One should be able to use it
|
||||
comfortably with a 60% keyboard and no pointing device.
|
||||
|
||||
haven serves as a testing ground, leaning on the side of compromises. It aims
|
||||
to use today's Linux desktop as a support, relying on X11/Wayland, existing
|
||||
window managers and web browsers.
|
||||
|
||||
The focus is therefore on going breadth-first, not depth-first. Applications
|
||||
only need to be good enough to be able to replace their older siblings at all.
|
||||
I.e. for me personally.
|
||||
|
||||
Scope
|
||||
-----
|
||||
Subproject names aim to have the minimum viable, reasonably identifiable name.
|
||||
To group them together, a common prefix of "h" is used. The second column is
|
||||
what should be used as the name in .desktop files, just like the GNOME project
|
||||
figured out it would make sense:
|
||||
|
||||
- hbe - bitmap editor
|
||||
- hbfe - bitmap font editor
|
||||
- he - text editor
|
||||
- hfm - file manager
|
||||
- hm - mail client
|
||||
- hnc - netcat-alike
|
||||
- ho - all-powerful organizer
|
||||
- hsm - system monitor
|
||||
- hss - spreadsheets
|
||||
- htd - translation dictionary
|
||||
- ht - terminal emulator
|
||||
- htk - GUI toolkit library
|
||||
|
||||
See Projects for more information about the individual projects.
|
||||
|
||||
Some taken names in Debian: hd (important), hte, hy.
|
||||
|
||||
Projects
|
||||
--------
|
||||
These are sorted in the order in which they should be created in order to gain
|
||||
the best possible momentum. The htk GUI toolkit is implied as a side product
|
||||
permeating the entire list.
|
||||
|
||||
Some information is omitted from these descriptions and lies either in my head
|
||||
or in my other notes.
|
||||
|
||||
hnc -- netcat-alike
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
An improved replacement for autocutsel in selection synchronization "mode":
|
||||
|
||||
- using only one OS process;
|
||||
- not polling selections twice a second unnecessarily;
|
||||
- calling SetSelectionOwner on change even when it already owns the selection,
|
||||
so that XFIXES SelectionNotify events are delivered;
|
||||
- not using cut buffers for anything.
|
||||
|
||||
Only UTF8_STRING-convertible selections are synchronized.
|
||||
|
||||
hswg -- static website 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.
|
||||
|
||||
he -- text editor
|
||||
~~~~~~~~~~~~~~~~~
|
||||
VIM controls, no scripting, no syntax highlight, single-file, made for
|
||||
variable-width/proportional fonts. Initially done primarily to produce a text
|
||||
editing widget, which is going to be an interesting challenge, arguably better
|
||||
solved by whole program composition. Scintilla may provide some inspiration.
|
||||
|
||||
In the second stage, support for the Language Server Protocol will be added so
|
||||
that the project can be edited using its own tools. Some scripting, perhaps
|
||||
a tiny subset of VimL, might be desirable. Or other means of configuration.
|
||||
|
||||
Visual block mode or the color column may still be implemented.
|
||||
|
||||
The real model for the editor is Qt Creator with FakeVIM, though this is not to
|
||||
be a clone of it, e.g. the various "Output" lists could be just special buffers,
|
||||
which may be have names starting on "// ".
|
||||
|
||||
.Resources:
|
||||
- http://doc.cat-v.org/plan_9/4th_edition/papers/sam/
|
||||
|
||||
ho -- all-powerful organizer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Zettelkasten with fulltext search, arbitrary reciprocal links, arbitrary tags.
|
||||
Flat storage. Should be able to use translation dictionaries for search hints.
|
||||
|
||||
Indexing and search may be based on a common database, no need to get all fancy:
|
||||
|
||||
- http://rachbelaid.com/postgres-full-text-search-is-good-enough/
|
||||
- https://www.sqlite.org/fts3.html#full_text_index_queries (FTS4 seems better)
|
||||
|
||||
htd -- translation dictionary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
This specific kind of application doesn't need a lot of user interface either,
|
||||
just a tab bar, text entry and two columns of text with simple formatting.
|
||||
|
||||
For simplicity we will establish a custom dictionary format based on either
|
||||
simple compress/gzip with separate files in StarDict style or, since we don't
|
||||
really strive for random access and memory-efficiency (those 120M that sdtui
|
||||
takes with my 10 dictionaries isn't particularly bad), pack everything with
|
||||
archive/zip.
|
||||
|
||||
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.
|
||||
|
||||
hfm -- file manager
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
All we need to achieve here is replace Midnight Commander, which besides the
|
||||
most basic features includes a VFS for archives. The editing widget in
|
||||
read-only mode could be used for F3. The shell is going to work very simply,
|
||||
creating a PTY device and running things under TERM=dumb while decoding SGR,
|
||||
or one could decide to run a new terminal emulator with a different shortcut.
|
||||
ht could probably also be integrated.
|
||||
|
||||
Eventually the number of panels should be arbitrary with proper shortcuts for
|
||||
working with them. We might also integrate a special view for picture previews,
|
||||
which might or might not deserve its own program.
|
||||
|
||||
hss -- spreadsheets
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
The first version doesn't need to be able to reference other cells, and can more
|
||||
or less be a CSV editor.
|
||||
|
||||
We can take inspiration from Excel:
|
||||
|
||||
- https://docs.microsoft.com/en-us/office/client-developer/excel/excel-recalculation
|
||||
- https://www.microsoft.com/en-us/research/uploads/prod/2018/03/build-systems.pdf
|
||||
|
||||
The rest
|
||||
~~~~~~~~
|
||||
Currently there are no significant, specific plans about the other applications.
|
||||
26
go.mod
Normal file
26
go.mod
Normal file
@@ -0,0 +1,26 @@
|
||||
module janouch.name/haven
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802
|
||||
github.com/bytesparadise/libasciidoc v0.7.1-0.20221008082129-967103fe8df6
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
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
|
||||
)
|
||||
418
go.sum
Normal file
418
go.sum
Normal file
@@ -0,0 +1,418 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 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/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=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bytesparadise/libasciidoc v0.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=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/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.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/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/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=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/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.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=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/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=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 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/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mna/pigeon v1.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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nxadm/tail v1.4.4/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.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/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=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.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/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.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=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.3.0/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=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-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=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-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=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-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-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/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=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190830223141-573d9926052a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-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=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/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/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/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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.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=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
@@ -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"
|
||||
3457
hid/main.go
3457
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 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.
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018, Přemysl Janouch <p@janouch.name>
|
||||
// Copyright (c) 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.
|
||||
|
||||
@@ -92,7 +92,7 @@ func getProperty(window xproto.Window, property xproto.Atom) (
|
||||
// chunking the requests. This has a cost of losing atomicity, although
|
||||
// it shouldn't pose a problem except for timeout-caused INCR races.
|
||||
var result xproto.GetPropertyReply
|
||||
for result.Length == 0 || result.BytesAfter > 0 {
|
||||
for (result.Sequence == 0 && result.Length == 0) || result.BytesAfter > 0 {
|
||||
reply, err := xproto.GetProperty(X, false, /* delete */
|
||||
window, property, xproto.GetPropertyTypeAny,
|
||||
uint32(len(result.Value))/4,
|
||||
|
||||
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.
|
||||
@@ -1,20 +1,11 @@
|
||||
// Program hasp is a preprocessor for libasciidoc to make it understand
|
||||
// two-line/underlined titles, intended to be used in Gitea.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/bytesparadise/libasciidoc"
|
||||
"github.com/bytesparadise/libasciidoc/pkg/renderer"
|
||||
)
|
||||
|
||||
// isTitle returns the title level if the lines seem to form a title,
|
||||
@@ -61,31 +52,3 @@ func ConvertTitles(w *io.PipeWriter, input []byte) {
|
||||
}
|
||||
writeLine(w, last, nil)
|
||||
}
|
||||
|
||||
func main() {
|
||||
input, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
go func() {
|
||||
defer pw.Close()
|
||||
ConvertTitles(pw, input)
|
||||
}()
|
||||
|
||||
// io.Copy(os.Stdout, pr)
|
||||
// return
|
||||
|
||||
_, err = libasciidoc.ConvertToHTML(context.Background(), pr, os.Stdout,
|
||||
renderer.IncludeHeaderFooter(true))
|
||||
if err != nil {
|
||||
// Fallback: output all the text sanitized for direct inclusion.
|
||||
os.Stdout.WriteString("<pre>")
|
||||
for _, line := range bytes.Split(input, []byte{'\n'}) {
|
||||
xml.EscapeText(os.Stdout, line)
|
||||
os.Stdout.WriteString("\n")
|
||||
}
|
||||
os.Stdout.WriteString("</pre>")
|
||||
}
|
||||
}
|
||||
529
hswg/main.go
Normal file
529
hswg/main.go
Normal file
@@ -0,0 +1,529 @@
|
||||
// Program hswg is a static website generator employing libasciidoc with added
|
||||
// support for two-line/underlined titles, and postprocessing "wiki" InterLinks.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/bytesparadise/libasciidoc/pkg/configuration"
|
||||
"github.com/bytesparadise/libasciidoc/pkg/parser"
|
||||
"github.com/bytesparadise/libasciidoc/pkg/renderer/sgml/html5"
|
||||
"github.com/bytesparadise/libasciidoc/pkg/types"
|
||||
"github.com/bytesparadise/libasciidoc/pkg/validator"
|
||||
)
|
||||
|
||||
// Metadata contains select metadata about a rendered document.
|
||||
type Metadata struct {
|
||||
types.Metadata
|
||||
|
||||
// Note that this includes entries from the front-matter
|
||||
// (see parser.ApplySubstitutions <- parser.ParseDocument).
|
||||
Attributes types.Attributes
|
||||
}
|
||||
|
||||
// IsDraft returns whether the document is marked as a draft, and should not
|
||||
// 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) (
|
||||
html *bytes.Buffer, meta Metadata, err error) {
|
||||
html = bytes.NewBuffer(nil)
|
||||
|
||||
var input []byte
|
||||
if input, err = ioutil.ReadAll(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
go func() {
|
||||
defer pw.Close()
|
||||
ConvertTitles(pw, input)
|
||||
}()
|
||||
|
||||
// io.Copy(os.Stdout, pr)
|
||||
// return
|
||||
|
||||
var doc *types.Document
|
||||
if doc, err = parser.ParseDocument(pr, config); err == nil {
|
||||
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)
|
||||
}
|
||||
meta.Metadata, err = html5.Render(doc, config, html)
|
||||
}
|
||||
if err != nil {
|
||||
// Fallback: output all the text sanitized for direct inclusion.
|
||||
html.Reset()
|
||||
|
||||
_, _ = html.WriteString("<pre>")
|
||||
for _, line := range bytes.Split(input, []byte{'\n'}) {
|
||||
_ = xml.EscapeText(html, line)
|
||||
_, _ = html.WriteString("\n")
|
||||
}
|
||||
_, _ = html.WriteString("</pre>")
|
||||
}
|
||||
meta.Attributes = config.Attributes
|
||||
return
|
||||
}
|
||||
|
||||
// Entry contains all context information about a single page.
|
||||
type Entry struct {
|
||||
Metadata // metadata
|
||||
PathSource string // path to source AsciiDoc
|
||||
PathDestination string // path to destination HTML
|
||||
mtime time.Time // modification time
|
||||
raw []byte // raw inner document
|
||||
Content template.HTML // inner document with expanded LinkWords
|
||||
backlinks map[string]bool // what documents link back here
|
||||
Backlinks []template.HTML
|
||||
}
|
||||
|
||||
// Published returns the date when the entry was published, or nil if unknown.
|
||||
func (e *Entry) Published() *time.Time {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
globs = []string{"*.adoc", "*.asciidoc"}
|
||||
extRE = regexp.MustCompile(`\.[^/.]*$`)
|
||||
)
|
||||
|
||||
func pathToName(path string) string {
|
||||
return stripExtension(filepath.Base(path))
|
||||
}
|
||||
|
||||
func stripExtension(path string) string {
|
||||
return extRE.ReplaceAllString(path, "")
|
||||
}
|
||||
|
||||
func resultPath(path string) string {
|
||||
if m := extRE.FindStringIndex(path); m != nil {
|
||||
return path[:m[0]] + ".html"
|
||||
}
|
||||
return path + ".html"
|
||||
}
|
||||
|
||||
func makeLink(m *map[string]*Entry, name string) string {
|
||||
e := (*m)[name]
|
||||
return fmt.Sprintf("<a href='%s'>%s</a>",
|
||||
filepath.Clean(e.PathDestination), name)
|
||||
}
|
||||
|
||||
var linkWordRE = regexp.MustCompile(`\b\p{Lu}\p{L}*\b`)
|
||||
|
||||
func expand(m *map[string]*Entry, name string, chunk []byte) []byte {
|
||||
return linkWordRE.ReplaceAllFunc(chunk, func(match []byte) []byte {
|
||||
if link, ok := (*m)[string(match)]; ok && string(match) != name &&
|
||||
!link.IsDraft() {
|
||||
link.backlinks[name] = true
|
||||
return []byte(makeLink(m, string(match)))
|
||||
}
|
||||
return match
|
||||
})
|
||||
}
|
||||
|
||||
var tagRE = regexp.MustCompile(`<[^<>]+>`)
|
||||
|
||||
func renderEntry(name string, e *Entry) error {
|
||||
f, err := os.Open(e.PathSource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i, err := f.Stat(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
e.mtime = i.ModTime()
|
||||
}
|
||||
|
||||
var html *bytes.Buffer
|
||||
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
|
||||
}
|
||||
|
||||
// Every page needs to have a title.
|
||||
if e.Title == "" {
|
||||
e.Title = name
|
||||
}
|
||||
|
||||
e.raw = html.Bytes()
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeEntry(path string) *Entry {
|
||||
return &Entry{
|
||||
PathSource: path,
|
||||
PathDestination: resultPath(path),
|
||||
}
|
||||
}
|
||||
|
||||
// loadEntries creates a map from document names to their page entries.
|
||||
func loadEntries(dirname string) (map[string]*Entry, error) {
|
||||
entries := map[string]*Entry{}
|
||||
for _, glob := range globs {
|
||||
matches, err := filepath.Glob(filepath.Join(dirname, glob))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", dirname, err)
|
||||
}
|
||||
for _, path := range matches {
|
||||
name := pathToName(path)
|
||||
if conflict, ok := entries[name]; ok {
|
||||
return nil, fmt.Errorf("%s: conflicts with %s",
|
||||
name, conflict.PathSource)
|
||||
}
|
||||
entries[name] = makeEntry(path)
|
||||
}
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func writeEntry(e *Entry, t *template.Template,
|
||||
entries *map[string]*Entry) error {
|
||||
f, err := os.Create(e.PathDestination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
backlinks := []string{}
|
||||
for name := range e.backlinks {
|
||||
backlinks = append(backlinks, name)
|
||||
}
|
||||
sort.Strings(backlinks)
|
||||
for _, name := range backlinks {
|
||||
e.Backlinks =
|
||||
append(e.Backlinks, template.HTML(makeLink(entries, name)))
|
||||
}
|
||||
|
||||
return t.Execute(f, e)
|
||||
}
|
||||
|
||||
func writeIndex(path string, t *template.Template,
|
||||
entries *map[string]*Entry) error {
|
||||
// Reorder entries reversely, primarily by date, secondarily by filename.
|
||||
ordered := []*Entry{}
|
||||
for _, e := range *entries {
|
||||
ordered = append(ordered, e)
|
||||
}
|
||||
|
||||
sort.Slice(ordered, func(i, j int) bool {
|
||||
a, b := ordered[i], ordered[j]
|
||||
p1, p2 := a.Published(), b.Published()
|
||||
if p1 == nil && p2 != nil {
|
||||
return true
|
||||
}
|
||||
if p1 == nil && p2 == nil {
|
||||
return a.PathSource > b.PathSource
|
||||
}
|
||||
if p2 == nil {
|
||||
return false
|
||||
}
|
||||
if p1.Equal(*p2) {
|
||||
return a.PathSource > b.PathSource
|
||||
}
|
||||
return p2.Before(*p1)
|
||||
})
|
||||
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(p): Splitting content to categories would be nice. Or tags.
|
||||
return t.Execute(f, ordered)
|
||||
}
|
||||
|
||||
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 {
|
||||
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.
|
||||
raw, last, expanded := e.raw, 0, bytes.NewBuffer(nil)
|
||||
for _, where := range tagRE.FindAllIndex(raw, -1) {
|
||||
_, _ = expanded.Write(expand(entries, name, raw[last:where[0]]))
|
||||
_, _ = expanded.Write(raw[where[0]:where[1]])
|
||||
last = where[1]
|
||||
}
|
||||
_, _ = expanded.Write(expand(entries, name, raw[last:]))
|
||||
e.Content = template.HTML(expanded.String())
|
||||
}
|
||||
for name, e := range *entries {
|
||||
// Don't overwrite failed renders.
|
||||
if e.raw == nil {
|
||||
continue
|
||||
}
|
||||
if err := writeEntry(e, t, entries); err != nil {
|
||||
log.Printf("%s: %s\n", name, err)
|
||||
}
|
||||
}
|
||||
if err := writeIndex(indexPath, indexT, entries); err != nil {
|
||||
log.Printf("%s: %s\n", indexPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
type watchEvent struct {
|
||||
path string // the path of the target
|
||||
present bool // if not, the file has been removed
|
||||
}
|
||||
|
||||
func dispatchEvents(dirname string, r io.Reader, ch chan<- *watchEvent) error {
|
||||
var e syscall.InotifyEvent
|
||||
for {
|
||||
// FIXME(p): This has to respect the machine's endianness.
|
||||
// Perhaps use the unsafe package.
|
||||
err := binary.Read(r, binary.LittleEndian, &e)
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
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")
|
||||
case e.Mask&syscall.IN_Q_OVERFLOW != 0:
|
||||
log.Println("inotify: queue overflowed")
|
||||
ch <- nil
|
||||
continue
|
||||
case e.Len == 0:
|
||||
continue
|
||||
}
|
||||
|
||||
basename, interesting := string(base[:bytes.IndexByte(base, 0)]), false
|
||||
for _, glob := range globs {
|
||||
if matches, _ := filepath.Match(glob, basename); matches {
|
||||
interesting = true
|
||||
}
|
||||
}
|
||||
if !interesting {
|
||||
continue
|
||||
}
|
||||
|
||||
event := &watchEvent{path: filepath.Join(dirname, basename)}
|
||||
if e.Mask&syscall.IN_MODIFY != 0 || e.Mask&syscall.IN_MOVED_TO != 0 ||
|
||||
e.Mask&syscall.IN_CLOSE_WRITE != 0 {
|
||||
event.present = true
|
||||
ch <- event
|
||||
}
|
||||
if e.Mask&syscall.IN_DELETE != 0 || e.Mask&syscall.IN_MOVED_FROM != 0 {
|
||||
event.present = false
|
||||
ch <- event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func watchDirectory(dirname string) (<-chan *watchEvent, error) {
|
||||
inotifyFD, err := syscall.InotifyInit1(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We're ignoring IN_CREATE, as it doesn't seem to be useful,
|
||||
// and we're leaving out IN_MODIFY since VIM always triggers IN_CLOSE_WRITE,
|
||||
// saving us from having to coalesce plentiful similar events.
|
||||
_, err = syscall.InotifyAddWatch(inotifyFD, dirname, syscall.IN_ONLYDIR|
|
||||
syscall.IN_MOVE|syscall.IN_DELETE|syscall.IN_CLOSE_WRITE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inotifyFile := os.NewFile(uintptr(inotifyFD), "inotify")
|
||||
buf := make([]byte, syscall.SizeofInotifyEvent+syscall.PathMax+1)
|
||||
ch := make(chan *watchEvent)
|
||||
go func() {
|
||||
// Trigger an initial rendering run.
|
||||
ch <- nil
|
||||
|
||||
defer close(ch)
|
||||
for {
|
||||
n, err := inotifyFile.Read(buf)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = dispatchEvents(dirname, bytes.NewReader(buf[:n]), ch)
|
||||
if err != nil {
|
||||
log.Printf("inotify: %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
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 {
|
||||
log.Println(err)
|
||||
} else if meta.Title != "" {
|
||||
_, _ = os.Stdout.WriteString("<h1>")
|
||||
_ = xml.EscapeText(os.Stdout, []byte(meta.Title))
|
||||
_, _ = os.Stdout.WriteString("</h1>\n")
|
||||
}
|
||||
_, _ = io.Copy(os.Stdout, html)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
singleFile()
|
||||
return
|
||||
}
|
||||
if len(os.Args) != 4 {
|
||||
log.Fatalf("usage: %s TEMPLATE INDEX DIRECTORY\n", os.Args[0])
|
||||
}
|
||||
|
||||
argTemplate, argIndex, argDirectory := os.Args[1], os.Args[2], os.Args[3]
|
||||
|
||||
// Read a template for entries.
|
||||
header, err := ioutil.ReadFile(argTemplate)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
tmplEntry, err := template.New("entry").Funcs(funcs).Parse(string(header))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Read a template for the index from the standard input.
|
||||
index, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
tmplIndex, err := template.New("index").Funcs(funcs).Parse(string(index))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Re-render as needed, avoid having to trigger anything manually.
|
||||
var entries map[string]*Entry
|
||||
directoryWatch, err := watchDirectory(argDirectory)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM)
|
||||
for {
|
||||
select {
|
||||
case <-signals:
|
||||
os.Exit(0)
|
||||
case event, ok := <-directoryWatch:
|
||||
if !ok {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
log.Println("reloading all files")
|
||||
if entries, err = loadEntries(argDirectory); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
} else if event.present {
|
||||
log.Printf("updating %s\n", event.path)
|
||||
entries[pathToName(event.path)] = makeEntry(event.path)
|
||||
} else {
|
||||
log.Printf("removing %s\n", event.path)
|
||||
delete(entries, pathToName(event.path))
|
||||
os.Remove(resultPath(event.path))
|
||||
}
|
||||
|
||||
finalizeEntries(&entries, tmplEntry, argIndex, tmplIndex)
|
||||
log.Println("done")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,4 +23,4 @@ Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||
fangyuanziti <tiziyuanfang@gmail.com>
|
||||
Bryan Matsuo <bryan.matsuo@gmail.com>
|
||||
Rabin Vincent <rabin@rab.in>
|
||||
Přemysl Janouch <p@janouch.name>
|
||||
Přemysl Eric Janouch <p@janouch.name>
|
||||
|
||||
@@ -32,4 +32,4 @@ Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||
fangyuanziti <tiziyuanfang@gmail.com>
|
||||
Bryan Matsuo <bryan.matsuo@gmail.com>
|
||||
Rabin Vincent <rabin@rab.in>
|
||||
Přemysl Janouch <p@janouch.name>
|
||||
Přemysl Eric Janouch <p@janouch.name>
|
||||
|
||||
@@ -12,8 +12,8 @@ Quick usage
|
||||
go get janouch.name/haven/nexgb
|
||||
go run $GOPATH/src/janouch.name/haven/nexgb/examples/create-window/main.go
|
||||
|
||||
Přemysl Janouch's fork
|
||||
----------------------
|
||||
Přemysl Eric Janouch's fork
|
||||
---------------------------
|
||||
I've merged BurntSushi/xgb into haven as a subdirectory due to a/ inactivity
|
||||
upstream, and b/ intentions to make incompatible changes meant to be in sync
|
||||
with the rest of the project.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Copyright (c) 2012 - 2016, Andrew Gallant <jamslam@gmail.com>
|
||||
Copyright (c) 2018, Přemysl Janouch <p@janouch.name>
|
||||
Copyright (c) 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018, Přemysl Janouch <p@janouch.name>
|
||||
// Copyright (c) 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.
|
||||
|
||||
@@ -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,17 +105,36 @@ 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 {
|
||||
@@ -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