Compare commits

...

59 Commits

Author SHA1 Message Date
486b58525f Add a basic tool for collecting web comments 2024-11-03 06:12:31 +01:00
c3cc608570 hswg: bump libasciidoc to master 2022-10-08 17:00:55 +02:00
d643187333 hswg: preset some attributes 2022-10-05 20:38:27 +02:00
103704b183 Punt hid back where it came from 2022-09-26 13:37:51 +02:00
18e8e11ad4 Further reduce scope
The idea of hic now lives as xP within the xK project,
and the idea of hib has been implemented within xC.
2022-09-25 23:57:19 +02:00
1528ed2db0 Reduce scope
I've already built an X11-capable MPD client, and getting the right
kind of FFT for spectrum analysis would be difficult without Cgo.
Native Go PulseAudio interfacing would similarly cause excess work.

The image viewer would be a lot worse in this regard, seeing as
the amount of preexisting native Go code is tiny, and it's slow.

TL;DR: These problems have already been resolved in nncmpp and fiv,
and there's no need for inferior alternatives.
2022-08-23 03:33:27 +02:00
5f0d5bca70 hid: bump the FD limit 2022-08-02 22:10:31 +02:00
442fa5d660 Bump libasciidoc 2022-03-20 23:28:45 +01:00
8b376694d3 hid: make note of a deprecation 2022-03-16 12:57:00 +01:00
22e3861851 hswg: use a buffered channel for signals
Found by go vet.
2022-03-16 12:33:25 +01:00
9603456cd6 hid: add WebIRC support
Such clients can only be identified through STATS L.

It's a bit weird to abuse the "port" field this way,
but right now, it serves its purpose.
2022-03-15 19:57:31 +01:00
b832a38ca6 hswg: parallelize rendering 2022-03-03 12:57:38 +01:00
6353dd156a hswg: log the error message on 📅 parse fail 2022-02-28 10:44:32 +01:00
7a2ea02c8d hswg: make AttrList return nil for missing attrs
And update copyright years.
2022-02-28 05:05:52 +01:00
bafd5ef221 hid: implement WALLOPS 2022-02-05 00:31:34 +01:00
ca245e4aca xgb-image: fix visual searching 2021-11-15 12:12:23 +01:00
c3905349b0 hswg: don't eat libasciidoc rendering errors
An unfortunate consequence of the := operator's behaviour.

Also, update copyright years.
2021-09-23 20:58:59 +02:00
f9e1f9a244 Bump Go modules to 1.17 2021-08-19 05:35:01 +02:00
4aab0b22ae hid: reflect the original project's new name
Better keep all schizophreny in my own head, rather than all projects.
2021-08-06 17:31:32 +02:00
5ab2977548 xgb-image: seek 32-bit visuals along with 30-bit
We only tried to upgrade to 32-bit depth when we weren't looking
for 30-bit visuals.  Probably of no practical consequence.
2021-08-01 03:36:23 +02:00
a927713a81 xgb-image: support 10-bit colours
Apparently, a DefaultDepth 30 Xserver won't do translucency.
2021-07-15 01:49:37 +02:00
5ae8c24b8d xgb-image: gofmt 2021-07-15 01:49:34 +02:00
ef24d7980c hswg: improve inotify processing
Make sure to read the whole record before checking flags.
2021-07-06 01:15:44 +02:00
6228693b22 Update .gitignore 2021-06-30 06:24:59 +02:00
be27f00685 hswg: add .Attr, .AttrList, contains
Trying to figure out a sensible way of handle tags.
2021-06-29 04:14:47 +02:00
61083027a3 hswg: split out asciidoc.go 2021-06-29 04:14:47 +02:00
5b432fcc0b hswg: add a minimal README.adoc
Moving the example script from somewhere else.
2021-06-27 00:01:22 +02:00
04e19f5186 hswg: use inotify to watch for changed documents
Now we force the glob to be *.adoc, as well as *.asciidoc,
and there can only be one document directory.

The previous single-run mode is no longer supported.
2021-06-22 23:25:02 +02:00
49a685c32e hswg: take output path for the index as argument 2021-06-22 23:25:02 +02:00
d763ce619d hswg: separate rendering from link expansion 2021-06-22 23:25:02 +02:00
8276f6bcb9 hswg: an initial attempt at refactoring main() 2021-06-22 23:25:02 +02:00
dd5c583e8b hswg: store backlinks in a map 2021-06-22 23:25:01 +02:00
63d18d068d hswg: actually use templates for output files 2021-06-22 01:01:43 +02:00
d47a8d2237 Bump libasciidoc dependency 2021-06-02 22:56:49 +02:00
a979edf5b7 Bump libasciidoc dependency
Now at a usable release version again.
2020-10-04 15:31:24 +02:00
9db34a955b Bump libasciidoc dependency 2020-09-30 03:00:00 +02:00
35974efe21 hswg: try to order entries by date, reverse order 2020-09-21 22:44:12 +02:00
8f542c7120 hswg: execute a template given on standard input
So that information can be extracted from documents easily.
2020-09-21 19:26:55 +02:00
ea8c59961c hswg: don't link to drafts 2020-09-21 19:26:54 +02:00
750f2139f5 hswg: extract attributes from documents 2020-09-21 19:26:54 +02:00
3d002bc540 Bump libasciidoc dependency 2020-09-21 19:26:54 +02:00
084a0a94b0 hswg: avoid self-referential links 2020-08-18 06:35:32 +02:00
91b1120c4a hswg: bump libasciidoc to a dev version
We want:
 - curved quotation marks
 - image alignment/float setting
2020-08-17 04:40:20 +02:00
f7f892fb59 hswg: deduplicate backlinks 2020-08-15 07:20:04 +02:00
d0ce3e3e66 Update README.adoc 2020-08-15 06:10:05 +02:00
3a5cc216bb hswg: merge in hasp as a mode
No need to have the two-line header processor in two places.
2020-08-15 04:26:50 +02:00
a049249d81 hswg: add a static website generator 2020-08-15 04:26:50 +02:00
d4eb9cde39 Update README.adoc 2020-08-12 01:52:09 +02:00
cb1c8f8563 Render the README as AsciiDoc
The little issues aren't worth the monospace font in Gitea.
2020-08-12 01:42:31 +02:00
13275f1dd3 Update .gitignore 2020-08-06 19:04:11 +02:00
030a23c1a2 hasp: bump libasciidoc and other dependencies 2020-08-01 14:02:03 +02:00
0d37e5bc8a Name change 2020-08-01 14:01:58 +02:00
eae39b13c2 hid: mention Go 1.12 alternative to TLS autodetection 2019-02-27 02:36:04 +01:00
95f183aa48 hpcu: eliminate infinite looping 2019-02-04 09:27:10 +01:00
e7ea35f304 Use Go modules 2018-12-01 22:52:17 +01:00
056391eeca hpcu: the slightest cleanup 2018-11-01 11:38:17 +01:00
f99615c850 Make README more AsciiDoc-compatible
It seems to almost work, except for callouts without blocks.
2018-10-08 03:54:57 +02:00
d04c140a69 ht: add generated wcwidth tables and algorithm 2018-10-07 18:09:09 +02:00
cd6c9e4d8c ht: add generated X11 keysym maps
Now we can make sense of keysyms and translate them to text.
2018-10-07 18:09:09 +02:00
28 changed files with 9573 additions and 4256 deletions

16
.gitignore vendored
View File

@@ -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

View File

@@ -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.

291
README
View File

@@ -1,291 +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
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
View 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
View 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
View 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=

View File

@@ -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 "}"
}'

View File

@@ -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"

File diff suppressed because it is too large Load Diff

View File

@@ -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.
}

View File

@@ -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.

View File

@@ -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,
@@ -133,18 +133,16 @@ func requestOwnership(origin *selectionState, time xproto.Timestamp) {
}
}
func handleEvent(ev nexgb.Event) {
switch e := ev.(type) {
case xfixes.SelectionNotifyEvent:
func handleXfixesSelectionNotify(e xfixes.SelectionNotifyEvent) {
state, ok := selections[e.Selection]
if !ok {
break
return
}
// Ownership request has been granted, don't ask ourselves for data.
if e.Owner == wid {
state.owning = e.SelectionTimestamp
break
return
}
// This should always be true.
@@ -155,7 +153,7 @@ func handleEvent(ev nexgb.Event) {
// Not checking whether we should give up when our current retrieval
// attempt is interrupted--the timeout mostly solves this.
if e.Owner == xproto.WindowNone {
break
return
}
// Don't try to process two things at once. Each request gets a few
@@ -163,7 +161,7 @@ func handleEvent(ev nexgb.Event) {
// doesn't commence. Ideally we'd set up a separate queue for these
// skipped requests and process them later.
if state.inProgress != 0 && e.Timestamp-state.inProgress < 5000 {
break
return
}
// ICCCM says we should ensure the named property doesn't exist.
@@ -174,22 +172,23 @@ func handleEvent(ev nexgb.Event) {
state.inProgress = e.Timestamp
state.incr = false
}
case xproto.SelectionNotifyEvent:
func handleSelectionNotify(e xproto.SelectionNotifyEvent) {
state, ok := selections[e.Selection]
if e.Requestor != wid || !ok || e.Time != state.inProgress {
break
return
}
state.inProgress = 0
if e.Property == xproto.AtomNone {
break
return
}
state.buffer = nil
reply, err := getProperty(e.Requestor, e.Property)
if err != nil {
break
return
}
// When you select a lot of text in VIM, it starts the ICCCM
@@ -203,18 +202,19 @@ func handleEvent(ev nexgb.Event) {
}
_ = xproto.DeleteProperty(X, e.Requestor, e.Property)
}
case xproto.PropertyNotifyEvent:
func handlePropertyNotify(e xproto.PropertyNotifyEvent) {
state, ok := selections[e.Atom]
if e.Window != wid || e.State != xproto.PropertyNewValue ||
!ok || !state.incr {
break
return
}
reply, err := getProperty(e.Window, e.Atom)
if err != nil {
state.incrFailed = true
break
return
}
if !appendText(state, reply) {
@@ -232,7 +232,9 @@ func handleEvent(ev nexgb.Event) {
_ = xproto.DeleteProperty(X, e.Window, e.Atom)
case xproto.SelectionRequestEvent:
}
func handleSelectionRequest(e xproto.SelectionRequestEvent) {
property := e.Property
if property == xproto.AtomNone {
property = e.Target
@@ -240,7 +242,7 @@ func handleEvent(ev nexgb.Event) {
state, ok := selections[e.Selection]
if e.Owner != wid || !ok {
break
return
}
var (
@@ -307,6 +309,18 @@ func handleEvent(ev nexgb.Event) {
_ = xproto.SendEvent(X, false /* propagate */, e.Requestor,
0 /* event mask */, string(response.Bytes()))
}
func handleXEvent(ev nexgb.Event) {
switch e := ev.(type) {
case xfixes.SelectionNotifyEvent:
handleXfixesSelectionNotify(e)
case xproto.SelectionNotifyEvent:
handleSelectionNotify(e)
case xproto.PropertyNotifyEvent:
handlePropertyNotify(e)
case xproto.SelectionRequestEvent:
handleSelectionRequest(e)
}
}
@@ -345,7 +359,7 @@ func main() {
return
}
if ev != nil {
handleEvent(ev)
handleXEvent(ev)
}
}
}

101
hswc/main.go Normal file
View 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
View 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.

View File

@@ -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
View 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")
}
}
}

49
ht/gen-keysyms.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/sh
gofmt <<EOF | sed 's, *//$,,'
// Code generated by running "go generate" in janouch.name/haven. DO NOT EDIT.
package $GOPACKAGE
import "janouch.name/haven/nexgb/xproto"
$(curl --silent --show-error \
https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h \
https://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h \
| perl -lne '
next unless /^\#define\s+
(XF86)?(XK_)([a-zA-Z_0-9]+)\s+
0x([0-9a-fA-F]+)\s*
(?:\/\*\s*(.*?)\s*\*\/)?\s*
$/x;
my ($name, $ident, $hex, $comment) =
(($1 // "") . $3, ($1 // "") . $2 . $3, lc $4, ($5 // ""));
# They are already somewhat sorted in the source file.
push @a, { hex => $hex, ident => $ident, comment => $comment };
$nametokeysym{$name} = $ident;
# All but the first name listed should be considered deprecated.
$keysymtoname{$ident} = $name unless exists $seen{$hex};
$seen{$hex}++;
END {
print "const (";
print "$_->{ident} = 0x$_->{hex} // $_->{comment}" for @a;
print ")";
# Very large tables, should be an on-demand package :(
print "// KeysymToName maps X11 keysym constants to their names";
print "var KeysymToName = map[xproto.Keysym]string{";
print "$_: \"$keysymtoname{$_}\"," for sort keys %keysymtoname;
print "}";
print "// NameToKeysym maps X11 keysym names to their constants";
print "var NameToKeysym = map[string]xproto.Keysym{";
print "\"$_\": $nametokeysym{$_}," for sort keys %nametokeysym;
print "}";
}
')
EOF

84
ht/gen-rune-width.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/bin/sh
u=https://www.unicode.org/Public/
# Download and filter Unicode data files with the given category expression,
# producing a list of possibly duplicitous codepoints in decimal format
retrieve() {
curl --silent --show-error --location "$2" | perl -lne 's/#.*//; s/ //g;
next unless /^([0-9A-F]+)(?:\.\.([0-9A-F]+))?;('"$1"')$/;
print for hex $1 .. hex ($2 // $1);'
}
togo() {
sort -nu | perl -lne '
sub flush { printf "{0x%04x, 0x%04x},\n", $first, $last }
BEGIN { $first = $last = <> }
if ($_ != $last + 1) { flush; $first = $_; }
$last = $_;
END { flush if defined $first }' | column -xc 72
}
gofmt <<EOF
// Code generated by running "go generate" in janouch.name/haven. DO NOT EDIT.
package $GOPACKAGE
// RuneWidth returns the column width of Go runes, using an algorithm and tables
// derived from https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c:
// - The null character (U+0000) has a column width of 0.
// - Other C0/C1 control characters and DEL will lead to a return value of -1.
// - Non-spacing and enclosing combining characters (general category code
// Mn or Me in the Unicode database) have a column width of 0.
// - SOFT HYPHEN (U+00AD) has a column width of 1.
// - Other format characters (general category code Cf in the Unicode database)
// and ZERO WIDTH SPACE (U+200B) have a column width of 0.
// - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) have
// a column width of 0.
// - Spacing characters in the East Asian Wide (W) or East Asian Full-width (F)
// category as defined in Unicode UAX #11 have a column width of 2.
// - All remaining characters (including all printable ISO 8859-1 and WGL4
// characters, Unicode control characters, etc.) have a column width of 1.
//
// Local changes:
// - Tables are generated from the latest available version of Unicode.
func RuneWidth(r rune) int {
switch {
case r == 0:
return 0
case r < 32 || r >= 0x7f && r < 0xa0:
return -1
case zeroWidthRunes.contains(r):
return 0
case fullWidthRunes.contains(r):
return 2
}
return 1
}
type runeRange struct{ first, last rune }
type runeRangeTable []runeRange
func (table runeRangeTable) contains(r rune) bool {
min, max := 0, len(table)-1
for max >= min {
mid := (min + max) / 2
if table[mid].last < r {
min = mid + 1
} else if table[mid].first > r {
max = mid - 1
} else {
return true
}
}
return false
}
var zeroWidthRunes = runeRangeTable{
$({ retrieve 'Me|Mn|Cf' $u/UCD/latest/ucd/extracted/DerivedGeneralCategory.txt;
seq 0x1160 0x11ff; echo $((0x200B)); } | grep -xv $((0x00AD)) | togo)
}
var fullWidthRunes = runeRangeTable{
$(retrieve 'W|F' $u/UCD/latest/ucd/EastAsianWidth.txt | togo)
}
EOF

49
ht/gen-unicode-map.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/sh
gofmt <<EOF
// Code generated by running "go generate" in janouch.name/haven. DO NOT EDIT.
package $GOPACKAGE
import "janouch.name/haven/nexgb/xproto"
// KeysymToRune tries to translate an X11 keysym to an appropriate rune.
// Returns -1 when no match is found.
func KeysymToRune(ks xproto.Keysym) rune {
// Visible Latin-1 is mapped 1:1
if (ks >= 0x20 && ks <= 0x7e) || (ks >= 0xa0 && ks <= 0xff) {
return rune(ks)
}
// Directly encoded 24-bit Unicode (going even above plane 16)
if (ks & 0xff000000) == 0x01000000 {
return rune(ks & 0x00ffffff)
}
min, max := 0, len(keysymToRuneTable)-1
for max >= min {
mid := (min + max) / 2
if keysymToRuneTable[mid].keysym < ks {
min = mid + 1
} else if keysymToRuneTable[mid].keysym > ks {
max = mid - 1
} else {
return keysymToRuneTable[mid].unicode
}
}
return -1
}
var keysymToRuneTable = []struct{
keysym xproto.Keysym
unicode rune
}{
$(curl --silent --show-error --location \
https://invisible-island.net/datafiles/release/xterm.tar.gz | \
tar --wildcards -xzOf - 'xterm-*/unicode/keysym.map' | \
sort | perl -lne '
next unless /^(0x([0-9a-f]{4}))\s+U([0-9a-f]{4})\s*(?:\#\s*(.*))?$/;
my ($keysym, $ks, $unicode, $comment) = ($1, hex($2), $3, ($4 // ""));
print "{$keysym, 0x$unicode}, // $comment"
if $ks >= 0x100 && $unicode ne "0000";
')
}
EOF

6761
ht/keysyms.go Normal file

File diff suppressed because it is too large Load Diff

204
ht/rune_width.go Normal file
View File

@@ -0,0 +1,204 @@
// Code generated by running "go generate" in janouch.name/haven. DO NOT EDIT.
package main
// RuneWidth returns the column width of Go runes, using an algorithm and tables
// derived from https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c:
// - The null character (U+0000) has a column width of 0.
// - Other C0/C1 control characters and DEL will lead to a return value of -1.
// - Non-spacing and enclosing combining characters (general category code
// Mn or Me in the Unicode database) have a column width of 0.
// - SOFT HYPHEN (U+00AD) has a column width of 1.
// - Other format characters (general category code Cf in the Unicode database)
// and ZERO WIDTH SPACE (U+200B) have a column width of 0.
// - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) have
// a column width of 0.
// - Spacing characters in the East Asian Wide (W) or East Asian Full-width (F)
// category as defined in Unicode UAX #11 have a column width of 2.
// - All remaining characters (including all printable ISO 8859-1 and WGL4
// characters, Unicode control characters, etc.) have a column width of 1.
//
// Local changes:
// - Tables are generated from the latest available version of Unicode.
func RuneWidth(r rune) int {
switch {
case r == 0:
return 0
case r < 32 || r >= 0x7f && r < 0xa0:
return -1
case zeroWidthRunes.contains(r):
return 0
case fullWidthRunes.contains(r):
return 2
}
return 1
}
type runeRange struct{ first, last rune }
type runeRangeTable []runeRange
func (table runeRangeTable) contains(r rune) bool {
min, max := 0, len(table)-1
for max >= min {
mid := (min + max) / 2
if table[mid].last < r {
min = mid + 1
} else if table[mid].first > r {
max = mid - 1
} else {
return true
}
}
return false
}
var zeroWidthRunes = runeRangeTable{
{0x0300, 0x036f}, {0x0483, 0x0489}, {0x0591, 0x05bd},
{0x05bf, 0x05bf}, {0x05c1, 0x05c2}, {0x05c4, 0x05c5},
{0x05c7, 0x05c7}, {0x0600, 0x0605}, {0x0610, 0x061a},
{0x061c, 0x061c}, {0x064b, 0x065f}, {0x0670, 0x0670},
{0x06d6, 0x06dd}, {0x06df, 0x06e4}, {0x06e7, 0x06e8},
{0x06ea, 0x06ed}, {0x070f, 0x070f}, {0x0711, 0x0711},
{0x0730, 0x074a}, {0x07a6, 0x07b0}, {0x07eb, 0x07f3},
{0x07fd, 0x07fd}, {0x0816, 0x0819}, {0x081b, 0x0823},
{0x0825, 0x0827}, {0x0829, 0x082d}, {0x0859, 0x085b},
{0x08d3, 0x0902}, {0x093a, 0x093a}, {0x093c, 0x093c},
{0x0941, 0x0948}, {0x094d, 0x094d}, {0x0951, 0x0957},
{0x0962, 0x0963}, {0x0981, 0x0981}, {0x09bc, 0x09bc},
{0x09c1, 0x09c4}, {0x09cd, 0x09cd}, {0x09e2, 0x09e3},
{0x09fe, 0x09fe}, {0x0a01, 0x0a02}, {0x0a3c, 0x0a3c},
{0x0a41, 0x0a42}, {0x0a47, 0x0a48}, {0x0a4b, 0x0a4d},
{0x0a51, 0x0a51}, {0x0a70, 0x0a71}, {0x0a75, 0x0a75},
{0x0a81, 0x0a82}, {0x0abc, 0x0abc}, {0x0ac1, 0x0ac5},
{0x0ac7, 0x0ac8}, {0x0acd, 0x0acd}, {0x0ae2, 0x0ae3},
{0x0afa, 0x0aff}, {0x0b01, 0x0b01}, {0x0b3c, 0x0b3c},
{0x0b3f, 0x0b3f}, {0x0b41, 0x0b44}, {0x0b4d, 0x0b4d},
{0x0b56, 0x0b56}, {0x0b62, 0x0b63}, {0x0b82, 0x0b82},
{0x0bc0, 0x0bc0}, {0x0bcd, 0x0bcd}, {0x0c00, 0x0c00},
{0x0c04, 0x0c04}, {0x0c3e, 0x0c40}, {0x0c46, 0x0c48},
{0x0c4a, 0x0c4d}, {0x0c55, 0x0c56}, {0x0c62, 0x0c63},
{0x0c81, 0x0c81}, {0x0cbc, 0x0cbc}, {0x0cbf, 0x0cbf},
{0x0cc6, 0x0cc6}, {0x0ccc, 0x0ccd}, {0x0ce2, 0x0ce3},
{0x0d00, 0x0d01}, {0x0d3b, 0x0d3c}, {0x0d41, 0x0d44},
{0x0d4d, 0x0d4d}, {0x0d62, 0x0d63}, {0x0dca, 0x0dca},
{0x0dd2, 0x0dd4}, {0x0dd6, 0x0dd6}, {0x0e31, 0x0e31},
{0x0e34, 0x0e3a}, {0x0e47, 0x0e4e}, {0x0eb1, 0x0eb1},
{0x0eb4, 0x0eb9}, {0x0ebb, 0x0ebc}, {0x0ec8, 0x0ecd},
{0x0f18, 0x0f19}, {0x0f35, 0x0f35}, {0x0f37, 0x0f37},
{0x0f39, 0x0f39}, {0x0f71, 0x0f7e}, {0x0f80, 0x0f84},
{0x0f86, 0x0f87}, {0x0f8d, 0x0f97}, {0x0f99, 0x0fbc},
{0x0fc6, 0x0fc6}, {0x102d, 0x1030}, {0x1032, 0x1037},
{0x1039, 0x103a}, {0x103d, 0x103e}, {0x1058, 0x1059},
{0x105e, 0x1060}, {0x1071, 0x1074}, {0x1082, 0x1082},
{0x1085, 0x1086}, {0x108d, 0x108d}, {0x109d, 0x109d},
{0x1160, 0x11ff}, {0x135d, 0x135f}, {0x1712, 0x1714},
{0x1732, 0x1734}, {0x1752, 0x1753}, {0x1772, 0x1773},
{0x17b4, 0x17b5}, {0x17b7, 0x17bd}, {0x17c6, 0x17c6},
{0x17c9, 0x17d3}, {0x17dd, 0x17dd}, {0x180b, 0x180e},
{0x1885, 0x1886}, {0x18a9, 0x18a9}, {0x1920, 0x1922},
{0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193b},
{0x1a17, 0x1a18}, {0x1a1b, 0x1a1b}, {0x1a56, 0x1a56},
{0x1a58, 0x1a5e}, {0x1a60, 0x1a60}, {0x1a62, 0x1a62},
{0x1a65, 0x1a6c}, {0x1a73, 0x1a7c}, {0x1a7f, 0x1a7f},
{0x1ab0, 0x1abe}, {0x1b00, 0x1b03}, {0x1b34, 0x1b34},
{0x1b36, 0x1b3a}, {0x1b3c, 0x1b3c}, {0x1b42, 0x1b42},
{0x1b6b, 0x1b73}, {0x1b80, 0x1b81}, {0x1ba2, 0x1ba5},
{0x1ba8, 0x1ba9}, {0x1bab, 0x1bad}, {0x1be6, 0x1be6},
{0x1be8, 0x1be9}, {0x1bed, 0x1bed}, {0x1bef, 0x1bf1},
{0x1c2c, 0x1c33}, {0x1c36, 0x1c37}, {0x1cd0, 0x1cd2},
{0x1cd4, 0x1ce0}, {0x1ce2, 0x1ce8}, {0x1ced, 0x1ced},
{0x1cf4, 0x1cf4}, {0x1cf8, 0x1cf9}, {0x1dc0, 0x1df9},
{0x1dfb, 0x1dff}, {0x200b, 0x200f}, {0x202a, 0x202e},
{0x2060, 0x2064}, {0x2066, 0x206f}, {0x20d0, 0x20f0},
{0x2cef, 0x2cf1}, {0x2d7f, 0x2d7f}, {0x2de0, 0x2dff},
{0x302a, 0x302d}, {0x3099, 0x309a}, {0xa66f, 0xa672},
{0xa674, 0xa67d}, {0xa69e, 0xa69f}, {0xa6f0, 0xa6f1},
{0xa802, 0xa802}, {0xa806, 0xa806}, {0xa80b, 0xa80b},
{0xa825, 0xa826}, {0xa8c4, 0xa8c5}, {0xa8e0, 0xa8f1},
{0xa8ff, 0xa8ff}, {0xa926, 0xa92d}, {0xa947, 0xa951},
{0xa980, 0xa982}, {0xa9b3, 0xa9b3}, {0xa9b6, 0xa9b9},
{0xa9bc, 0xa9bc}, {0xa9e5, 0xa9e5}, {0xaa29, 0xaa2e},
{0xaa31, 0xaa32}, {0xaa35, 0xaa36}, {0xaa43, 0xaa43},
{0xaa4c, 0xaa4c}, {0xaa7c, 0xaa7c}, {0xaab0, 0xaab0},
{0xaab2, 0xaab4}, {0xaab7, 0xaab8}, {0xaabe, 0xaabf},
{0xaac1, 0xaac1}, {0xaaec, 0xaaed}, {0xaaf6, 0xaaf6},
{0xabe5, 0xabe5}, {0xabe8, 0xabe8}, {0xabed, 0xabed},
{0xfb1e, 0xfb1e}, {0xfe00, 0xfe0f}, {0xfe20, 0xfe2f},
{0xfeff, 0xfeff}, {0xfff9, 0xfffb}, {0x101fd, 0x101fd},
{0x102e0, 0x102e0}, {0x10376, 0x1037a}, {0x10a01, 0x10a03},
{0x10a05, 0x10a06}, {0x10a0c, 0x10a0f}, {0x10a38, 0x10a3a},
{0x10a3f, 0x10a3f}, {0x10ae5, 0x10ae6}, {0x10d24, 0x10d27},
{0x10f46, 0x10f50}, {0x11001, 0x11001}, {0x11038, 0x11046},
{0x1107f, 0x11081}, {0x110b3, 0x110b6}, {0x110b9, 0x110ba},
{0x110bd, 0x110bd}, {0x110cd, 0x110cd}, {0x11100, 0x11102},
{0x11127, 0x1112b}, {0x1112d, 0x11134}, {0x11173, 0x11173},
{0x11180, 0x11181}, {0x111b6, 0x111be}, {0x111c9, 0x111cc},
{0x1122f, 0x11231}, {0x11234, 0x11234}, {0x11236, 0x11237},
{0x1123e, 0x1123e}, {0x112df, 0x112df}, {0x112e3, 0x112ea},
{0x11300, 0x11301}, {0x1133b, 0x1133c}, {0x11340, 0x11340},
{0x11366, 0x1136c}, {0x11370, 0x11374}, {0x11438, 0x1143f},
{0x11442, 0x11444}, {0x11446, 0x11446}, {0x1145e, 0x1145e},
{0x114b3, 0x114b8}, {0x114ba, 0x114ba}, {0x114bf, 0x114c0},
{0x114c2, 0x114c3}, {0x115b2, 0x115b5}, {0x115bc, 0x115bd},
{0x115bf, 0x115c0}, {0x115dc, 0x115dd}, {0x11633, 0x1163a},
{0x1163d, 0x1163d}, {0x1163f, 0x11640}, {0x116ab, 0x116ab},
{0x116ad, 0x116ad}, {0x116b0, 0x116b5}, {0x116b7, 0x116b7},
{0x1171d, 0x1171f}, {0x11722, 0x11725}, {0x11727, 0x1172b},
{0x1182f, 0x11837}, {0x11839, 0x1183a}, {0x11a01, 0x11a0a},
{0x11a33, 0x11a38}, {0x11a3b, 0x11a3e}, {0x11a47, 0x11a47},
{0x11a51, 0x11a56}, {0x11a59, 0x11a5b}, {0x11a8a, 0x11a96},
{0x11a98, 0x11a99}, {0x11c30, 0x11c36}, {0x11c38, 0x11c3d},
{0x11c3f, 0x11c3f}, {0x11c92, 0x11ca7}, {0x11caa, 0x11cb0},
{0x11cb2, 0x11cb3}, {0x11cb5, 0x11cb6}, {0x11d31, 0x11d36},
{0x11d3a, 0x11d3a}, {0x11d3c, 0x11d3d}, {0x11d3f, 0x11d45},
{0x11d47, 0x11d47}, {0x11d90, 0x11d91}, {0x11d95, 0x11d95},
{0x11d97, 0x11d97}, {0x11ef3, 0x11ef4}, {0x16af0, 0x16af4},
{0x16b30, 0x16b36}, {0x16f8f, 0x16f92}, {0x1bc9d, 0x1bc9e},
{0x1bca0, 0x1bca3}, {0x1d167, 0x1d169}, {0x1d173, 0x1d182},
{0x1d185, 0x1d18b}, {0x1d1aa, 0x1d1ad}, {0x1d242, 0x1d244},
{0x1da00, 0x1da36}, {0x1da3b, 0x1da6c}, {0x1da75, 0x1da75},
{0x1da84, 0x1da84}, {0x1da9b, 0x1da9f}, {0x1daa1, 0x1daaf},
{0x1e000, 0x1e006}, {0x1e008, 0x1e018}, {0x1e01b, 0x1e021},
{0x1e023, 0x1e024}, {0x1e026, 0x1e02a}, {0x1e8d0, 0x1e8d6},
{0x1e944, 0x1e94a}, {0xe0001, 0xe0001}, {0xe0020, 0xe007f},
{0xe0100, 0xe01ef},
}
var fullWidthRunes = runeRangeTable{
{0x1100, 0x115f}, {0x231a, 0x231b}, {0x2329, 0x232a},
{0x23e9, 0x23ec}, {0x23f0, 0x23f0}, {0x23f3, 0x23f3},
{0x25fd, 0x25fe}, {0x2614, 0x2615}, {0x2648, 0x2653},
{0x267f, 0x267f}, {0x2693, 0x2693}, {0x26a1, 0x26a1},
{0x26aa, 0x26ab}, {0x26bd, 0x26be}, {0x26c4, 0x26c5},
{0x26ce, 0x26ce}, {0x26d4, 0x26d4}, {0x26ea, 0x26ea},
{0x26f2, 0x26f3}, {0x26f5, 0x26f5}, {0x26fa, 0x26fa},
{0x26fd, 0x26fd}, {0x2705, 0x2705}, {0x270a, 0x270b},
{0x2728, 0x2728}, {0x274c, 0x274c}, {0x274e, 0x274e},
{0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797},
{0x27b0, 0x27b0}, {0x27bf, 0x27bf}, {0x2b1b, 0x2b1c},
{0x2b50, 0x2b50}, {0x2b55, 0x2b55}, {0x2e80, 0x2e99},
{0x2e9b, 0x2ef3}, {0x2f00, 0x2fd5}, {0x2ff0, 0x2ffb},
{0x3000, 0x303e}, {0x3041, 0x3096}, {0x3099, 0x30ff},
{0x3105, 0x312f}, {0x3131, 0x318e}, {0x3190, 0x31ba},
{0x31c0, 0x31e3}, {0x31f0, 0x321e}, {0x3220, 0x3247},
{0x3250, 0x32fe}, {0x3300, 0x4dbf}, {0x4e00, 0xa48c},
{0xa490, 0xa4c6}, {0xa960, 0xa97c}, {0xac00, 0xd7a3},
{0xf900, 0xfaff}, {0xfe10, 0xfe19}, {0xfe30, 0xfe52},
{0xfe54, 0xfe66}, {0xfe68, 0xfe6b}, {0xff01, 0xff60},
{0xffe0, 0xffe6}, {0x16fe0, 0x16fe1}, {0x17000, 0x187f1},
{0x18800, 0x18af2}, {0x1b000, 0x1b11e}, {0x1b170, 0x1b2fb},
{0x1f004, 0x1f004}, {0x1f0cf, 0x1f0cf}, {0x1f18e, 0x1f18e},
{0x1f191, 0x1f19a}, {0x1f200, 0x1f202}, {0x1f210, 0x1f23b},
{0x1f240, 0x1f248}, {0x1f250, 0x1f251}, {0x1f260, 0x1f265},
{0x1f300, 0x1f320}, {0x1f32d, 0x1f335}, {0x1f337, 0x1f37c},
{0x1f37e, 0x1f393}, {0x1f3a0, 0x1f3ca}, {0x1f3cf, 0x1f3d3},
{0x1f3e0, 0x1f3f0}, {0x1f3f4, 0x1f3f4}, {0x1f3f8, 0x1f43e},
{0x1f440, 0x1f440}, {0x1f442, 0x1f4fc}, {0x1f4ff, 0x1f53d},
{0x1f54b, 0x1f54e}, {0x1f550, 0x1f567}, {0x1f57a, 0x1f57a},
{0x1f595, 0x1f596}, {0x1f5a4, 0x1f5a4}, {0x1f5fb, 0x1f64f},
{0x1f680, 0x1f6c5}, {0x1f6cc, 0x1f6cc}, {0x1f6d0, 0x1f6d2},
{0x1f6eb, 0x1f6ec}, {0x1f6f4, 0x1f6f9}, {0x1f910, 0x1f93e},
{0x1f940, 0x1f970}, {0x1f973, 0x1f976}, {0x1f97a, 0x1f97a},
{0x1f97c, 0x1f9a2}, {0x1f9b0, 0x1f9b9}, {0x1f9c0, 0x1f9c2},
{0x1f9d0, 0x1f9ff}, {0x20000, 0x2fffd}, {0x30000, 0x3fffd},
}

859
ht/unicode_map.go Normal file
View File

@@ -0,0 +1,859 @@
// Code generated by running "go generate" in janouch.name/haven. DO NOT EDIT.
package main
import "janouch.name/haven/nexgb/xproto"
// KeysymToRune tries to translate an X11 keysym to an appropriate rune.
// Returns -1 when no match is found.
func KeysymToRune(ks xproto.Keysym) rune {
// Visible Latin-1 is mapped 1:1
if (ks >= 0x20 && ks <= 0x7e) || (ks >= 0xa0 && ks <= 0xff) {
return rune(ks)
}
// Directly encoded 24-bit Unicode (going even above plane 16)
if (ks & 0xff000000) == 0x01000000 {
return rune(ks & 0x00ffffff)
}
min, max := 0, len(keysymToRuneTable)-1
for max >= min {
mid := (min + max) / 2
if keysymToRuneTable[mid].keysym < ks {
min = mid + 1
} else if keysymToRuneTable[mid].keysym > ks {
max = mid - 1
} else {
return keysymToRuneTable[mid].unicode
}
}
return -1
}
var keysymToRuneTable = []struct {
keysym xproto.Keysym
unicode rune
}{
{0x01a1, 0x0104}, // Aogonek
{0x01a2, 0x02d8}, // breve
{0x01a3, 0x0141}, // Lstroke
{0x01a5, 0x013d}, // Lcaron
{0x01a6, 0x015a}, // Sacute
{0x01a9, 0x0160}, // Scaron
{0x01aa, 0x015e}, // Scedilla
{0x01ab, 0x0164}, // Tcaron
{0x01ac, 0x0179}, // Zacute
{0x01ae, 0x017d}, // Zcaron
{0x01af, 0x017b}, // Zabovedot
{0x01b1, 0x0105}, // aogonek
{0x01b2, 0x02db}, // ogonek
{0x01b3, 0x0142}, // lstroke
{0x01b5, 0x013e}, // lcaron
{0x01b6, 0x015b}, // sacute
{0x01b7, 0x02c7}, // caron
{0x01b9, 0x0161}, // scaron
{0x01ba, 0x015f}, // scedilla
{0x01bb, 0x0165}, // tcaron
{0x01bc, 0x017a}, // zacute
{0x01bd, 0x02dd}, // doubleacute
{0x01be, 0x017e}, // zcaron
{0x01bf, 0x017c}, // zabovedot
{0x01c0, 0x0154}, // Racute
{0x01c3, 0x0102}, // Abreve
{0x01c5, 0x0139}, // Lacute
{0x01c6, 0x0106}, // Cacute
{0x01c8, 0x010c}, // Ccaron
{0x01ca, 0x0118}, // Eogonek
{0x01cc, 0x011a}, // Ecaron
{0x01cf, 0x010e}, // Dcaron
{0x01d0, 0x0110}, // Dstroke
{0x01d1, 0x0143}, // Nacute
{0x01d2, 0x0147}, // Ncaron
{0x01d5, 0x0150}, // Odoubleacute
{0x01d8, 0x0158}, // Rcaron
{0x01d9, 0x016e}, // Uring
{0x01db, 0x0170}, // Udoubleacute
{0x01de, 0x0162}, // Tcedilla
{0x01e0, 0x0155}, // racute
{0x01e3, 0x0103}, // abreve
{0x01e5, 0x013a}, // lacute
{0x01e6, 0x0107}, // cacute
{0x01e8, 0x010d}, // ccaron
{0x01ea, 0x0119}, // eogonek
{0x01ec, 0x011b}, // ecaron
{0x01ef, 0x010f}, // dcaron
{0x01f0, 0x0111}, // dstroke
{0x01f1, 0x0144}, // nacute
{0x01f2, 0x0148}, // ncaron
{0x01f5, 0x0151}, // odoubleacute
{0x01f8, 0x0159}, // rcaron
{0x01f9, 0x016f}, // uring
{0x01fb, 0x0171}, // udoubleacute
{0x01fe, 0x0163}, // tcedilla
{0x01ff, 0x02d9}, // abovedot
{0x02a1, 0x0126}, // Hstroke
{0x02a6, 0x0124}, // Hcircumflex
{0x02a9, 0x0130}, // Iabovedot
{0x02ab, 0x011e}, // Gbreve
{0x02ac, 0x0134}, // Jcircumflex
{0x02b1, 0x0127}, // hstroke
{0x02b6, 0x0125}, // hcircumflex
{0x02b9, 0x0131}, // idotless
{0x02bb, 0x011f}, // gbreve
{0x02bc, 0x0135}, // jcircumflex
{0x02c5, 0x010a}, // Cabovedot
{0x02c6, 0x0108}, // Ccircumflex
{0x02d5, 0x0120}, // Gabovedot
{0x02d8, 0x011c}, // Gcircumflex
{0x02dd, 0x016c}, // Ubreve
{0x02de, 0x015c}, // Scircumflex
{0x02e5, 0x010b}, // cabovedot
{0x02e6, 0x0109}, // ccircumflex
{0x02f5, 0x0121}, // gabovedot
{0x02f8, 0x011d}, // gcircumflex
{0x02fd, 0x016d}, // ubreve
{0x02fe, 0x015d}, // scircumflex
{0x03a2, 0x0138}, // kra
{0x03a3, 0x0156}, // Rcedilla
{0x03a5, 0x0128}, // Itilde
{0x03a6, 0x013b}, // Lcedilla
{0x03aa, 0x0112}, // Emacron
{0x03ab, 0x0122}, // Gcedilla
{0x03ac, 0x0166}, // Tslash
{0x03b3, 0x0157}, // rcedilla
{0x03b5, 0x0129}, // itilde
{0x03b6, 0x013c}, // lcedilla
{0x03ba, 0x0113}, // emacron
{0x03bb, 0x0123}, // gcedilla
{0x03bc, 0x0167}, // tslash
{0x03bd, 0x014a}, // ENG
{0x03bf, 0x014b}, // eng
{0x03c0, 0x0100}, // Amacron
{0x03c7, 0x012e}, // Iogonek
{0x03cc, 0x0116}, // Eabovedot
{0x03cf, 0x012a}, // Imacron
{0x03d1, 0x0145}, // Ncedilla
{0x03d2, 0x014c}, // Omacron
{0x03d3, 0x0136}, // Kcedilla
{0x03d9, 0x0172}, // Uogonek
{0x03dd, 0x0168}, // Utilde
{0x03de, 0x016a}, // Umacron
{0x03e0, 0x0101}, // amacron
{0x03e7, 0x012f}, // iogonek
{0x03ec, 0x0117}, // eabovedot
{0x03ef, 0x012b}, // imacron
{0x03f1, 0x0146}, // ncedilla
{0x03f2, 0x014d}, // omacron
{0x03f3, 0x0137}, // kcedilla
{0x03f9, 0x0173}, // uogonek
{0x03fd, 0x0169}, // utilde
{0x03fe, 0x016b}, // umacron
{0x047e, 0x203e}, // overline
{0x04a1, 0x3002}, // kana_fullstop
{0x04a2, 0x300c}, // kana_openingbracket
{0x04a3, 0x300d}, // kana_closingbracket
{0x04a4, 0x3001}, // kana_comma
{0x04a5, 0x30fb}, // kana_conjunctive
{0x04a6, 0x30f2}, // kana_WO
{0x04a7, 0x30a1}, // kana_a
{0x04a8, 0x30a3}, // kana_i
{0x04a9, 0x30a5}, // kana_u
{0x04aa, 0x30a7}, // kana_e
{0x04ab, 0x30a9}, // kana_o
{0x04ac, 0x30e3}, // kana_ya
{0x04ad, 0x30e5}, // kana_yu
{0x04ae, 0x30e7}, // kana_yo
{0x04af, 0x30c3}, // kana_tsu
{0x04b0, 0x30fc}, // prolongedsound
{0x04b1, 0x30a2}, // kana_A
{0x04b2, 0x30a4}, // kana_I
{0x04b3, 0x30a6}, // kana_U
{0x04b4, 0x30a8}, // kana_E
{0x04b5, 0x30aa}, // kana_O
{0x04b6, 0x30ab}, // kana_KA
{0x04b7, 0x30ad}, // kana_KI
{0x04b8, 0x30af}, // kana_KU
{0x04b9, 0x30b1}, // kana_KE
{0x04ba, 0x30b3}, // kana_KO
{0x04bb, 0x30b5}, // kana_SA
{0x04bc, 0x30b7}, // kana_SHI
{0x04bd, 0x30b9}, // kana_SU
{0x04be, 0x30bb}, // kana_SE
{0x04bf, 0x30bd}, // kana_SO
{0x04c0, 0x30bf}, // kana_TA
{0x04c1, 0x30c1}, // kana_CHI
{0x04c2, 0x30c4}, // kana_TSU
{0x04c3, 0x30c6}, // kana_TE
{0x04c4, 0x30c8}, // kana_TO
{0x04c5, 0x30ca}, // kana_NA
{0x04c6, 0x30cb}, // kana_NI
{0x04c7, 0x30cc}, // kana_NU
{0x04c8, 0x30cd}, // kana_NE
{0x04c9, 0x30ce}, // kana_NO
{0x04ca, 0x30cf}, // kana_HA
{0x04cb, 0x30d2}, // kana_HI
{0x04cc, 0x30d5}, // kana_FU
{0x04cd, 0x30d8}, // kana_HE
{0x04ce, 0x30db}, // kana_HO
{0x04cf, 0x30de}, // kana_MA
{0x04d0, 0x30df}, // kana_MI
{0x04d1, 0x30e0}, // kana_MU
{0x04d2, 0x30e1}, // kana_ME
{0x04d3, 0x30e2}, // kana_MO
{0x04d4, 0x30e4}, // kana_YA
{0x04d5, 0x30e6}, // kana_YU
{0x04d6, 0x30e8}, // kana_YO
{0x04d7, 0x30e9}, // kana_RA
{0x04d8, 0x30ea}, // kana_RI
{0x04d9, 0x30eb}, // kana_RU
{0x04da, 0x30ec}, // kana_RE
{0x04db, 0x30ed}, // kana_RO
{0x04dc, 0x30ef}, // kana_WA
{0x04dd, 0x30f3}, // kana_N
{0x04de, 0x309b}, // voicedsound
{0x04df, 0x309c}, // semivoicedsound
{0x05ac, 0x060c}, // Arabic_comma
{0x05bb, 0x061b}, // Arabic_semicolon
{0x05bf, 0x061f}, // Arabic_question_mark
{0x05c1, 0x0621}, // Arabic_hamza
{0x05c2, 0x0622}, // Arabic_maddaonalef
{0x05c3, 0x0623}, // Arabic_hamzaonalef
{0x05c4, 0x0624}, // Arabic_hamzaonwaw
{0x05c5, 0x0625}, // Arabic_hamzaunderalef
{0x05c6, 0x0626}, // Arabic_hamzaonyeh
{0x05c7, 0x0627}, // Arabic_alef
{0x05c8, 0x0628}, // Arabic_beh
{0x05c9, 0x0629}, // Arabic_tehmarbuta
{0x05ca, 0x062a}, // Arabic_teh
{0x05cb, 0x062b}, // Arabic_theh
{0x05cc, 0x062c}, // Arabic_jeem
{0x05cd, 0x062d}, // Arabic_hah
{0x05ce, 0x062e}, // Arabic_khah
{0x05cf, 0x062f}, // Arabic_dal
{0x05d0, 0x0630}, // Arabic_thal
{0x05d1, 0x0631}, // Arabic_ra
{0x05d2, 0x0632}, // Arabic_zain
{0x05d3, 0x0633}, // Arabic_seen
{0x05d4, 0x0634}, // Arabic_sheen
{0x05d5, 0x0635}, // Arabic_sad
{0x05d6, 0x0636}, // Arabic_dad
{0x05d7, 0x0637}, // Arabic_tah
{0x05d8, 0x0638}, // Arabic_zah
{0x05d9, 0x0639}, // Arabic_ain
{0x05da, 0x063a}, // Arabic_ghain
{0x05e0, 0x0640}, // Arabic_tatweel
{0x05e1, 0x0641}, // Arabic_feh
{0x05e2, 0x0642}, // Arabic_qaf
{0x05e3, 0x0643}, // Arabic_kaf
{0x05e4, 0x0644}, // Arabic_lam
{0x05e5, 0x0645}, // Arabic_meem
{0x05e6, 0x0646}, // Arabic_noon
{0x05e7, 0x0647}, // Arabic_ha
{0x05e8, 0x0648}, // Arabic_waw
{0x05e9, 0x0649}, // Arabic_alefmaksura
{0x05ea, 0x064a}, // Arabic_yeh
{0x05eb, 0x064b}, // Arabic_fathatan
{0x05ec, 0x064c}, // Arabic_dammatan
{0x05ed, 0x064d}, // Arabic_kasratan
{0x05ee, 0x064e}, // Arabic_fatha
{0x05ef, 0x064f}, // Arabic_damma
{0x05f0, 0x0650}, // Arabic_kasra
{0x05f1, 0x0651}, // Arabic_shadda
{0x05f2, 0x0652}, // Arabic_sukun
{0x06a1, 0x0452}, // Serbian_dje
{0x06a2, 0x0453}, // Macedonia_gje
{0x06a3, 0x0451}, // Cyrillic_io
{0x06a4, 0x0454}, // Ukrainian_ie
{0x06a5, 0x0455}, // Macedonia_dse
{0x06a6, 0x0456}, // Ukrainian_i
{0x06a7, 0x0457}, // Ukrainian_yi
{0x06a8, 0x0458}, // Cyrillic_je
{0x06a9, 0x0459}, // Cyrillic_lje
{0x06aa, 0x045a}, // Cyrillic_nje
{0x06ab, 0x045b}, // Serbian_tshe
{0x06ac, 0x045c}, // Macedonia_kje
{0x06ad, 0x0491}, // Ukrainian_ghe_with_upturn
{0x06ae, 0x045e}, // Byelorussian_shortu
{0x06af, 0x045f}, // Cyrillic_dzhe
{0x06b0, 0x2116}, // numerosign
{0x06b1, 0x0402}, // Serbian_DJE
{0x06b2, 0x0403}, // Macedonia_GJE
{0x06b3, 0x0401}, // Cyrillic_IO
{0x06b4, 0x0404}, // Ukrainian_IE
{0x06b5, 0x0405}, // Macedonia_DSE
{0x06b6, 0x0406}, // Ukrainian_I
{0x06b7, 0x0407}, // Ukrainian_YI
{0x06b8, 0x0408}, // Cyrillic_JE
{0x06b9, 0x0409}, // Cyrillic_LJE
{0x06ba, 0x040a}, // Cyrillic_NJE
{0x06bb, 0x040b}, // Serbian_TSHE
{0x06bc, 0x040c}, // Macedonia_KJE
{0x06bd, 0x0490}, // Ukrainian_GHE_WITH_UPTURN
{0x06be, 0x040e}, // Byelorussian_SHORTU
{0x06bf, 0x040f}, // Cyrillic_DZHE
{0x06c0, 0x044e}, // Cyrillic_yu
{0x06c1, 0x0430}, // Cyrillic_a
{0x06c2, 0x0431}, // Cyrillic_be
{0x06c3, 0x0446}, // Cyrillic_tse
{0x06c4, 0x0434}, // Cyrillic_de
{0x06c5, 0x0435}, // Cyrillic_ie
{0x06c6, 0x0444}, // Cyrillic_ef
{0x06c7, 0x0433}, // Cyrillic_ghe
{0x06c8, 0x0445}, // Cyrillic_ha
{0x06c9, 0x0438}, // Cyrillic_i
{0x06ca, 0x0439}, // Cyrillic_shorti
{0x06cb, 0x043a}, // Cyrillic_ka
{0x06cc, 0x043b}, // Cyrillic_el
{0x06cd, 0x043c}, // Cyrillic_em
{0x06ce, 0x043d}, // Cyrillic_en
{0x06cf, 0x043e}, // Cyrillic_o
{0x06d0, 0x043f}, // Cyrillic_pe
{0x06d1, 0x044f}, // Cyrillic_ya
{0x06d2, 0x0440}, // Cyrillic_er
{0x06d3, 0x0441}, // Cyrillic_es
{0x06d4, 0x0442}, // Cyrillic_te
{0x06d5, 0x0443}, // Cyrillic_u
{0x06d6, 0x0436}, // Cyrillic_zhe
{0x06d7, 0x0432}, // Cyrillic_ve
{0x06d8, 0x044c}, // Cyrillic_softsign
{0x06d9, 0x044b}, // Cyrillic_yeru
{0x06da, 0x0437}, // Cyrillic_ze
{0x06db, 0x0448}, // Cyrillic_sha
{0x06dc, 0x044d}, // Cyrillic_e
{0x06dd, 0x0449}, // Cyrillic_shcha
{0x06de, 0x0447}, // Cyrillic_che
{0x06df, 0x044a}, // Cyrillic_hardsign
{0x06e0, 0x042e}, // Cyrillic_YU
{0x06e1, 0x0410}, // Cyrillic_A
{0x06e2, 0x0411}, // Cyrillic_BE
{0x06e3, 0x0426}, // Cyrillic_TSE
{0x06e4, 0x0414}, // Cyrillic_DE
{0x06e5, 0x0415}, // Cyrillic_IE
{0x06e6, 0x0424}, // Cyrillic_EF
{0x06e7, 0x0413}, // Cyrillic_GHE
{0x06e8, 0x0425}, // Cyrillic_HA
{0x06e9, 0x0418}, // Cyrillic_I
{0x06ea, 0x0419}, // Cyrillic_SHORTI
{0x06eb, 0x041a}, // Cyrillic_KA
{0x06ec, 0x041b}, // Cyrillic_EL
{0x06ed, 0x041c}, // Cyrillic_EM
{0x06ee, 0x041d}, // Cyrillic_EN
{0x06ef, 0x041e}, // Cyrillic_O
{0x06f0, 0x041f}, // Cyrillic_PE
{0x06f1, 0x042f}, // Cyrillic_YA
{0x06f2, 0x0420}, // Cyrillic_ER
{0x06f3, 0x0421}, // Cyrillic_ES
{0x06f4, 0x0422}, // Cyrillic_TE
{0x06f5, 0x0423}, // Cyrillic_U
{0x06f6, 0x0416}, // Cyrillic_ZHE
{0x06f7, 0x0412}, // Cyrillic_VE
{0x06f8, 0x042c}, // Cyrillic_SOFTSIGN
{0x06f9, 0x042b}, // Cyrillic_YERU
{0x06fa, 0x0417}, // Cyrillic_ZE
{0x06fb, 0x0428}, // Cyrillic_SHA
{0x06fc, 0x042d}, // Cyrillic_E
{0x06fd, 0x0429}, // Cyrillic_SHCHA
{0x06fe, 0x0427}, // Cyrillic_CHE
{0x06ff, 0x042a}, // Cyrillic_HARDSIGN
{0x07a1, 0x0386}, // Greek_ALPHAaccent
{0x07a2, 0x0388}, // Greek_EPSILONaccent
{0x07a3, 0x0389}, // Greek_ETAaccent
{0x07a4, 0x038a}, // Greek_IOTAaccent
{0x07a5, 0x03aa}, // Greek_IOTAdieresis
{0x07a7, 0x038c}, // Greek_OMICRONaccent
{0x07a8, 0x038e}, // Greek_UPSILONaccent
{0x07a9, 0x03ab}, // Greek_UPSILONdieresis
{0x07ab, 0x038f}, // Greek_OMEGAaccent
{0x07ae, 0x0385}, // Greek_accentdieresis
{0x07af, 0x2015}, // Greek_horizbar
{0x07b1, 0x03ac}, // Greek_alphaaccent
{0x07b2, 0x03ad}, // Greek_epsilonaccent
{0x07b3, 0x03ae}, // Greek_etaaccent
{0x07b4, 0x03af}, // Greek_iotaaccent
{0x07b5, 0x03ca}, // Greek_IOTAdieresis
{0x07b6, 0x0390}, // Greek_iotaaccentdieresis
{0x07b7, 0x03cc}, // Greek_omicronaccent
{0x07b8, 0x03cd}, // Greek_upsilonaccent
{0x07b9, 0x03cb}, // Greek_upsilondieresis
{0x07ba, 0x03b0}, // Greek_upsilonaccentdieresis
{0x07bb, 0x03ce}, // Greek_omegaaccent
{0x07c1, 0x0391}, // Greek_ALPHA
{0x07c2, 0x0392}, // Greek_BETA
{0x07c3, 0x0393}, // Greek_GAMMA
{0x07c4, 0x0394}, // Greek_DELTA
{0x07c5, 0x0395}, // Greek_EPSILON
{0x07c6, 0x0396}, // Greek_ZETA
{0x07c7, 0x0397}, // Greek_ETA
{0x07c8, 0x0398}, // Greek_THETA
{0x07c9, 0x0399}, // Greek_IOTA
{0x07ca, 0x039a}, // Greek_KAPPA
{0x07cb, 0x039b}, // Greek_LAMBDA
{0x07cb, 0x039b}, // Greek_LAMDA
{0x07cc, 0x039c}, // Greek_MU
{0x07cd, 0x039d}, // Greek_NU
{0x07ce, 0x039e}, // Greek_XI
{0x07cf, 0x039f}, // Greek_OMICRON
{0x07d0, 0x03a0}, // Greek_PI
{0x07d1, 0x03a1}, // Greek_RHO
{0x07d2, 0x03a3}, // Greek_SIGMA
{0x07d4, 0x03a4}, // Greek_TAU
{0x07d5, 0x03a5}, // Greek_UPSILON
{0x07d6, 0x03a6}, // Greek_PHI
{0x07d7, 0x03a7}, // Greek_CHI
{0x07d8, 0x03a8}, // Greek_PSI
{0x07d9, 0x03a9}, // Greek_OMEGA
{0x07e1, 0x03b1}, // Greek_alpha
{0x07e2, 0x03b2}, // Greek_beta
{0x07e3, 0x03b3}, // Greek_gamma
{0x07e4, 0x03b4}, // Greek_delta
{0x07e5, 0x03b5}, // Greek_epsilon
{0x07e6, 0x03b6}, // Greek_zeta
{0x07e7, 0x03b7}, // Greek_eta
{0x07e8, 0x03b8}, // Greek_theta
{0x07e9, 0x03b9}, // Greek_iota
{0x07ea, 0x03ba}, // Greek_kappa
{0x07eb, 0x03bb}, // Greek_lambda
{0x07ec, 0x03bc}, // Greek_mu
{0x07ed, 0x03bd}, // Greek_nu
{0x07ee, 0x03be}, // Greek_xi
{0x07ef, 0x03bf}, // Greek_omicron
{0x07f0, 0x03c0}, // Greek_pi
{0x07f1, 0x03c1}, // Greek_rho
{0x07f2, 0x03c3}, // Greek_sigma
{0x07f3, 0x03c2}, // Greek_finalsmallsigma
{0x07f4, 0x03c4}, // Greek_tau
{0x07f5, 0x03c5}, // Greek_upsilon
{0x07f6, 0x03c6}, // Greek_phi
{0x07f7, 0x03c7}, // Greek_chi
{0x07f8, 0x03c8}, // Greek_psi
{0x07f9, 0x03c9}, // Greek_omega
{0x08a1, 0x23b7}, // leftradical
{0x08a2, 0x250c}, // topleftradical
{0x08a3, 0x2500}, // horizconnector
{0x08a4, 0x2320}, // topintegral
{0x08a5, 0x2321}, // botintegral
{0x08a6, 0x2502}, // vertconnector
{0x08a7, 0x23a1}, // topleftsqbracket
{0x08a8, 0x23a3}, // botleftsqbracket
{0x08a9, 0x23a4}, // toprightsqbracket
{0x08aa, 0x23a6}, // botrightsqbracket
{0x08ab, 0x239b}, // topleftparens
{0x08ac, 0x239d}, // botleftparens
{0x08ad, 0x239e}, // toprightparens
{0x08ae, 0x23a0}, // botrightparens
{0x08af, 0x23a8}, // leftmiddlecurlybrace
{0x08b0, 0x23ac}, // rightmiddlecurlybrace
{0x08bc, 0x2264}, // lessthanequal
{0x08bd, 0x2260}, // notequal
{0x08be, 0x2265}, // greaterthanequal
{0x08bf, 0x222b}, // integral
{0x08c0, 0x2234}, // therefore
{0x08c1, 0x221d}, // variation
{0x08c2, 0x221e}, // infinity
{0x08c5, 0x2207}, // nabla
{0x08c8, 0x223c}, // approximate
{0x08c9, 0x2243}, // similarequal
{0x08cd, 0x21d4}, // ifonlyif
{0x08ce, 0x21d2}, // implies
{0x08cf, 0x2261}, // identical
{0x08d6, 0x221a}, // radical
{0x08da, 0x2282}, // includedin
{0x08db, 0x2283}, // includes
{0x08dc, 0x2229}, // intersection
{0x08dd, 0x222a}, // union
{0x08de, 0x2227}, // logicaland
{0x08df, 0x2228}, // logicalor
{0x08ef, 0x2202}, // partialderivative
{0x08f6, 0x0192}, // function
{0x08fb, 0x2190}, // leftarrow
{0x08fc, 0x2191}, // uparrow
{0x08fd, 0x2192}, // rightarrow
{0x08fe, 0x2193}, // downarrow
{0x09df, 0x2422}, // blank
{0x09e0, 0x25c6}, // soliddiamond
{0x09e1, 0x2592}, // checkerboard
{0x09e2, 0x2409}, // ht
{0x09e3, 0x240c}, // ff
{0x09e4, 0x240d}, // cr
{0x09e5, 0x240a}, // lf
{0x09e8, 0x2424}, // nl
{0x09e9, 0x240b}, // vt
{0x09ea, 0x2518}, // lowrightcorner
{0x09eb, 0x2510}, // uprightcorner
{0x09ec, 0x250c}, // upleftcorner
{0x09ed, 0x2514}, // lowleftcorner
{0x09ee, 0x253c}, // crossinglines
{0x09ef, 0x23ba}, // horizlinescan1
{0x09f0, 0x23bb}, // horizlinescan3
{0x09f1, 0x2500}, // horizlinescan5
{0x09f2, 0x23bc}, // horizlinescan7
{0x09f3, 0x23bd}, // horizlinescan9
{0x09f4, 0x251c}, // leftt
{0x09f5, 0x2524}, // rightt
{0x09f6, 0x2534}, // bott
{0x09f7, 0x252c}, // topt
{0x09f8, 0x2502}, // vertbar
{0x0aa1, 0x2003}, // emspace
{0x0aa2, 0x2002}, // enspace
{0x0aa3, 0x2004}, // em3space
{0x0aa4, 0x2005}, // em4space
{0x0aa5, 0x2007}, // digitspace
{0x0aa6, 0x2008}, // punctspace
{0x0aa7, 0x2009}, // thinspace
{0x0aa8, 0x200a}, // hairspace
{0x0aa9, 0x2014}, // emdash
{0x0aaa, 0x2013}, // endash
{0x0aac, 0x2423}, // signifblank
{0x0aae, 0x2026}, // ellipsis
{0x0aaf, 0x2025}, // doubbaselinedot
{0x0ab0, 0x2153}, // onethird
{0x0ab1, 0x2154}, // twothirds
{0x0ab2, 0x2155}, // onefifth
{0x0ab3, 0x2156}, // twofifths
{0x0ab4, 0x2157}, // threefifths
{0x0ab5, 0x2158}, // fourfifths
{0x0ab6, 0x2159}, // onesixth
{0x0ab7, 0x215a}, // fivesixths
{0x0ab8, 0x2105}, // careof
{0x0abb, 0x2012}, // figdash
{0x0abc, 0x2329}, // leftanglebracket (not U+27E8)
{0x0abd, 0x002e}, // decimalpoint
{0x0abe, 0x232a}, // rightanglebracket (not U+27E9)
{0x0ac3, 0x215b}, // oneeighth
{0x0ac4, 0x215c}, // threeeighths
{0x0ac5, 0x215d}, // fiveeighths
{0x0ac6, 0x215e}, // seveneighths
{0x0ac9, 0x2122}, // trademark
{0x0aca, 0x2613}, // signaturemark
{0x0acc, 0x25c1}, // leftopentriangle
{0x0acd, 0x25b7}, // rightopentriangle
{0x0ace, 0x25cb}, // emopencircle
{0x0acf, 0x25af}, // emopenrectangle
{0x0ad0, 0x2018}, // leftsinglequotemark
{0x0ad1, 0x2019}, // rightsinglequotemark
{0x0ad2, 0x201c}, // leftdoublequotemark
{0x0ad3, 0x201d}, // rightdoublequotemark
{0x0ad4, 0x211e}, // prescription
{0x0ad5, 0x2030}, // per mille
{0x0ad6, 0x2032}, // minutes
{0x0ad7, 0x2033}, // seconds
{0x0ad9, 0x271d}, // latincross
{0x0adb, 0x25ac}, // filledrectbullet
{0x0adc, 0x25c0}, // filledlefttribullet
{0x0add, 0x25b6}, // filledrighttribullet
{0x0ade, 0x25cf}, // emfilledcircle
{0x0adf, 0x25ae}, // emfilledrect
{0x0ae0, 0x25e6}, // enopencircbullet
{0x0ae1, 0x25ab}, // enopensquarebullet
{0x0ae2, 0x25ad}, // openrectbullet
{0x0ae3, 0x25b3}, // opentribulletup
{0x0ae4, 0x25bd}, // opentribulletdown
{0x0ae5, 0x2606}, // openstar
{0x0ae6, 0x2022}, // enfilledcircbullet
{0x0ae7, 0x25aa}, // enfilledsqbullet
{0x0ae8, 0x25b2}, // filledtribulletup
{0x0ae9, 0x25bc}, // filledtribulletdown
{0x0aea, 0x261c}, // leftpointer
{0x0aeb, 0x261e}, // rightpointer
{0x0aec, 0x2663}, // club
{0x0aed, 0x2666}, // diamond
{0x0aee, 0x2665}, // heart
{0x0af0, 0x2720}, // maltesecross
{0x0af1, 0x2020}, // dagger
{0x0af2, 0x2021}, // doubledagger
{0x0af3, 0x2713}, // checkmark
{0x0af4, 0x2717}, // ballotcross
{0x0af5, 0x266f}, // musicalsharp
{0x0af6, 0x266d}, // musicalflat
{0x0af7, 0x2642}, // malesymbol
{0x0af8, 0x2640}, // femalesymbol
{0x0af9, 0x260e}, // telephone
{0x0afa, 0x2315}, // telephonerecorder
{0x0afb, 0x2117}, // phonographcopyright
{0x0afc, 0x2038}, // caret
{0x0afd, 0x201a}, // singlelowquotemark
{0x0afe, 0x201e}, // doublelowquotemark
{0x0ba3, 0x003c}, // leftcaret
{0x0ba6, 0x003e}, // rightcaret
{0x0ba8, 0x2228}, // downcaret
{0x0ba9, 0x2227}, // upcaret
{0x0bc0, 0x00af}, // overbar
{0x0bc2, 0x22a4}, // downtack
{0x0bc3, 0x2229}, // upshoe
{0x0bc4, 0x230a}, // downstile
{0x0bc6, 0x005f}, // underbar
{0x0bca, 0x2218}, // jot
{0x0bcc, 0x2395}, // quad
{0x0bce, 0x22a5}, // uptack
{0x0bcf, 0x25cb}, // circle
{0x0bd3, 0x2308}, // upstile
{0x0bd6, 0x222a}, // downshoe
{0x0bd8, 0x2283}, // rightshoe
{0x0bda, 0x2282}, // leftshoe
{0x0bdc, 0x22a3}, // lefttack
{0x0bfc, 0x22a2}, // righttack
{0x0cdf, 0x2017}, // hebrew_doublelowline
{0x0ce0, 0x05d0}, // hebrew_aleph
{0x0ce1, 0x05d1}, // hebrew_bet
{0x0ce2, 0x05d2}, // hebrew_gimel
{0x0ce3, 0x05d3}, // hebrew_dalet
{0x0ce4, 0x05d4}, // hebrew_he
{0x0ce5, 0x05d5}, // hebrew_waw
{0x0ce6, 0x05d6}, // hebrew_zain
{0x0ce7, 0x05d7}, // hebrew_chet
{0x0ce8, 0x05d8}, // hebrew_tet
{0x0ce9, 0x05d9}, // hebrew_yod
{0x0cea, 0x05da}, // hebrew_finalkaph
{0x0ceb, 0x05db}, // hebrew_kaph
{0x0cec, 0x05dc}, // hebrew_lamed
{0x0ced, 0x05dd}, // hebrew_finalmem
{0x0cee, 0x05de}, // hebrew_mem
{0x0cef, 0x05df}, // hebrew_finalnun
{0x0cf0, 0x05e0}, // hebrew_nun
{0x0cf1, 0x05e1}, // hebrew_samech
{0x0cf2, 0x05e2}, // hebrew_ayin
{0x0cf3, 0x05e3}, // hebrew_finalpe
{0x0cf4, 0x05e4}, // hebrew_pe
{0x0cf5, 0x05e5}, // hebrew_finalzade
{0x0cf6, 0x05e6}, // hebrew_zade
{0x0cf7, 0x05e7}, // hebrew_qoph
{0x0cf8, 0x05e8}, // hebrew_resh
{0x0cf9, 0x05e9}, // hebrew_shin
{0x0cfa, 0x05ea}, // hebrew_taw
{0x0da1, 0x0e01}, // Thai_kokai
{0x0da2, 0x0e02}, // Thai_khokhai
{0x0da3, 0x0e03}, // Thai_khokhuat
{0x0da4, 0x0e04}, // Thai_khokhwai
{0x0da5, 0x0e05}, // Thai_khokhon
{0x0da6, 0x0e06}, // Thai_khorakhang
{0x0da7, 0x0e07}, // Thai_ngongu
{0x0da8, 0x0e08}, // Thai_chochan
{0x0da9, 0x0e09}, // Thai_choching
{0x0daa, 0x0e0a}, // Thai_chochang
{0x0dab, 0x0e0b}, // Thai_soso
{0x0dac, 0x0e0c}, // Thai_chochoe
{0x0dad, 0x0e0d}, // Thai_yoying
{0x0dae, 0x0e0e}, // Thai_dochada
{0x0daf, 0x0e0f}, // Thai_topatak
{0x0db0, 0x0e10}, // Thai_thothan
{0x0db1, 0x0e11}, // Thai_thonangmontho
{0x0db2, 0x0e12}, // Thai_thophuthao
{0x0db3, 0x0e13}, // Thai_nonen
{0x0db4, 0x0e14}, // Thai_dodek
{0x0db5, 0x0e15}, // Thai_totao
{0x0db6, 0x0e16}, // Thai_thothung
{0x0db7, 0x0e17}, // Thai_thothahan
{0x0db8, 0x0e18}, // Thai_thothong
{0x0db9, 0x0e19}, // Thai_nonu
{0x0dba, 0x0e1a}, // Thai_bobaimai
{0x0dbb, 0x0e1b}, // Thai_popla
{0x0dbc, 0x0e1c}, // Thai_phophung
{0x0dbd, 0x0e1d}, // Thai_fofa
{0x0dbe, 0x0e1e}, // Thai_phophan
{0x0dbf, 0x0e1f}, // Thai_fofan
{0x0dc0, 0x0e20}, // Thai_phosamphao
{0x0dc1, 0x0e21}, // Thai_moma
{0x0dc2, 0x0e22}, // Thai_yoyak
{0x0dc3, 0x0e23}, // Thai_rorua
{0x0dc4, 0x0e24}, // Thai_ru
{0x0dc5, 0x0e25}, // Thai_loling
{0x0dc6, 0x0e26}, // Thai_lu
{0x0dc7, 0x0e27}, // Thai_wowaen
{0x0dc8, 0x0e28}, // Thai_sosala
{0x0dc9, 0x0e29}, // Thai_sorusi
{0x0dca, 0x0e2a}, // Thai_sosua
{0x0dcb, 0x0e2b}, // Thai_hohip
{0x0dcc, 0x0e2c}, // Thai_lochula
{0x0dcd, 0x0e2d}, // Thai_oang
{0x0dce, 0x0e2e}, // Thai_honokhuk
{0x0dcf, 0x0e2f}, // Thai_paiyannoi
{0x0dd0, 0x0e30}, // Thai_saraa
{0x0dd1, 0x0e31}, // Thai_maihanakat
{0x0dd2, 0x0e32}, // Thai_saraaa
{0x0dd3, 0x0e33}, // Thai_saraam
{0x0dd4, 0x0e34}, // Thai_sarai
{0x0dd5, 0x0e35}, // Thai_saraii
{0x0dd6, 0x0e36}, // Thai_saraue
{0x0dd7, 0x0e37}, // Thai_sarauee
{0x0dd8, 0x0e38}, // Thai_sarau
{0x0dd9, 0x0e39}, // Thai_sarauu
{0x0dda, 0x0e3a}, // Thai_phinthu
{0x0ddf, 0x0e3f}, // Thai_baht
{0x0de0, 0x0e40}, // Thai_sarae
{0x0de1, 0x0e41}, // Thai_saraae
{0x0de2, 0x0e42}, // Thai_sarao
{0x0de3, 0x0e43}, // Thai_saraaimaimuan
{0x0de4, 0x0e44}, // Thai_saraaimaimalai
{0x0de5, 0x0e45}, // Thai_lakkhangyao
{0x0de6, 0x0e46}, // Thai_maiyamok
{0x0de7, 0x0e47}, // Thai_maitaikhu
{0x0de8, 0x0e48}, // Thai_maiek
{0x0de9, 0x0e49}, // Thai_maitho
{0x0dea, 0x0e4a}, // Thai_maitri
{0x0deb, 0x0e4b}, // Thai_maichattawa
{0x0dec, 0x0e4c}, // Thai_thanthakhat
{0x0ded, 0x0e4d}, // Thai_nikhahit
{0x0df0, 0x0e50}, // Thai_leksun
{0x0df1, 0x0e51}, // Thai_leknung
{0x0df2, 0x0e52}, // Thai_leksong
{0x0df3, 0x0e53}, // Thai_leksam
{0x0df4, 0x0e54}, // Thai_leksi
{0x0df5, 0x0e55}, // Thai_lekha
{0x0df6, 0x0e56}, // Thai_lekhok
{0x0df7, 0x0e57}, // Thai_lekchet
{0x0df8, 0x0e58}, // Thai_lekpaet
{0x0df9, 0x0e59}, // Thai_lekkao
{0x0ea1, 0x3131}, // Hangul_Kiyeog
{0x0ea2, 0x3132}, // Hangul_SsangKiyeog
{0x0ea3, 0x3133}, // Hangul_KiyeogSios
{0x0ea4, 0x3134}, // Hangul_Nieun
{0x0ea5, 0x3135}, // Hangul_NieunJieuj
{0x0ea6, 0x3136}, // Hangul_NieunHieuh
{0x0ea7, 0x3137}, // Hangul_Dikeud
{0x0ea8, 0x3138}, // Hangul_SsangDikeud
{0x0ea9, 0x3139}, // Hangul_Rieul
{0x0eaa, 0x313a}, // Hangul_RieulKiyeog
{0x0eab, 0x313b}, // Hangul_RieulMieum
{0x0eac, 0x313c}, // Hangul_RieulPieub
{0x0ead, 0x313d}, // Hangul_RieulSios
{0x0eae, 0x313e}, // Hangul_RieulTieut
{0x0eaf, 0x313f}, // Hangul_RieulPhieuf
{0x0eb0, 0x3140}, // Hangul_RieulHieuh
{0x0eb1, 0x3141}, // Hangul_Mieum
{0x0eb2, 0x3142}, // Hangul_Pieub
{0x0eb3, 0x3143}, // Hangul_SsangPieub
{0x0eb4, 0x3144}, // Hangul_PieubSios
{0x0eb5, 0x3145}, // Hangul_Sios
{0x0eb6, 0x3146}, // Hangul_SsangSios
{0x0eb7, 0x3147}, // Hangul_Ieung
{0x0eb8, 0x3148}, // Hangul_Jieuj
{0x0eb9, 0x3149}, // Hangul_SsangJieuj
{0x0eba, 0x314a}, // Hangul_Cieuc
{0x0ebb, 0x314b}, // Hangul_Khieuq
{0x0ebc, 0x314c}, // Hangul_Tieut
{0x0ebd, 0x314d}, // Hangul_Phieuf
{0x0ebe, 0x314e}, // Hangul_Hieuh
{0x0ebf, 0x314f}, // Hangul_A
{0x0ec0, 0x3150}, // Hangul_AE
{0x0ec1, 0x3151}, // Hangul_YA
{0x0ec2, 0x3152}, // Hangul_YAE
{0x0ec3, 0x3153}, // Hangul_EO
{0x0ec4, 0x3154}, // Hangul_E
{0x0ec5, 0x3155}, // Hangul_YEO
{0x0ec6, 0x3156}, // Hangul_YE
{0x0ec7, 0x3157}, // Hangul_O
{0x0ec8, 0x3158}, // Hangul_WA
{0x0ec9, 0x3159}, // Hangul_WAE
{0x0eca, 0x315a}, // Hangul_OE
{0x0ecb, 0x315b}, // Hangul_YO
{0x0ecc, 0x315c}, // Hangul_U
{0x0ecd, 0x315d}, // Hangul_WEO
{0x0ece, 0x315e}, // Hangul_WE
{0x0ecf, 0x315f}, // Hangul_WI
{0x0ed0, 0x3160}, // Hangul_YU
{0x0ed1, 0x3161}, // Hangul_EU
{0x0ed2, 0x3162}, // Hangul_YI
{0x0ed3, 0x3163}, // Hangul_I
{0x0ed4, 0x11a8}, // Hangul_J_Kiyeog
{0x0ed5, 0x11a9}, // Hangul_J_SsangKiyeog
{0x0ed6, 0x11aa}, // Hangul_J_KiyeogSios
{0x0ed7, 0x11ab}, // Hangul_J_Nieun
{0x0ed8, 0x11ac}, // Hangul_J_NieunJieuj
{0x0ed9, 0x11ad}, // Hangul_J_NieunHieuh
{0x0eda, 0x11ae}, // Hangul_J_Dikeud
{0x0edb, 0x11af}, // Hangul_J_Rieul
{0x0edc, 0x11b0}, // Hangul_J_RieulKiyeog
{0x0edd, 0x11b1}, // Hangul_J_RieulMieum
{0x0ede, 0x11b2}, // Hangul_J_RieulPieub
{0x0edf, 0x11b3}, // Hangul_J_RieulSios
{0x0ee0, 0x11b4}, // Hangul_J_RieulTieut
{0x0ee1, 0x11b5}, // Hangul_J_RieulPhieuf
{0x0ee2, 0x11b6}, // Hangul_J_RieulHieuh
{0x0ee3, 0x11b7}, // Hangul_J_Mieum
{0x0ee4, 0x11b8}, // Hangul_J_Pieub
{0x0ee5, 0x11b9}, // Hangul_J_PieubSios
{0x0ee6, 0x11ba}, // Hangul_J_Sios
{0x0ee7, 0x11bb}, // Hangul_J_SsangSios
{0x0ee8, 0x11bc}, // Hangul_J_Ieung
{0x0ee9, 0x11bd}, // Hangul_J_Jieuj
{0x0eea, 0x11be}, // Hangul_J_Cieuc
{0x0eeb, 0x11bf}, // Hangul_J_Khieuq
{0x0eec, 0x11c0}, // Hangul_J_Tieut
{0x0eed, 0x11c1}, // Hangul_J_Phieuf
{0x0eee, 0x11c2}, // Hangul_J_Hieuh
{0x0eef, 0x316d}, // Hangul_RieulYeorinHieuh
{0x0ef0, 0x3171}, // Hangul_SunkyeongeumMieum
{0x0ef1, 0x3178}, // Hangul_SunkyeongeumPieub
{0x0ef2, 0x317f}, // Hangul_PanSios
{0x0ef3, 0x3181}, // Hangul_KkogjiDalrinIeung
{0x0ef4, 0x3184}, // Hangul_SunkyeongeumPhieuf
{0x0ef5, 0x3186}, // Hangul_YeorinHieuh
{0x0ef6, 0x318d}, // Hangul_AraeA
{0x0ef7, 0x318e}, // Hangul_AraeAE
{0x0ef8, 0x11eb}, // Hangul_J_PanSios
{0x0ef9, 0x11f0}, // Hangul_J_KkogjiDalrinIeung
{0x0efa, 0x11f9}, // Hangul_J_YeorinHieuh
{0x0eff, 0x20a9}, // Korean_Won
{0x13a4, 0x20ac}, // Euro
{0x13bc, 0x0152}, // OE
{0x13bd, 0x0153}, // oe
{0x13be, 0x0178}, // Ydiaeresis
{0x20a0, 0x20a0}, // EcuSign
{0x20a1, 0x20a1}, // ColonSign
{0x20a2, 0x20a2}, // CruzeiroSign
{0x20a3, 0x20a3}, // FFrancSign
{0x20a4, 0x20a4}, // LiraSign
{0x20a5, 0x20a5}, // MillSign
{0x20a6, 0x20a6}, // NairaSign
{0x20a7, 0x20a7}, // PesetaSign
{0x20a8, 0x20a8}, // RupeeSign
{0x20a9, 0x20a9}, // WonSign
{0x20aa, 0x20aa}, // NewSheqelSign
{0x20ab, 0x20ab}, // DongSign
{0x20ac, 0x20ac}, // EuroSign
{0xfe50, 0x0300}, // dead_grave
{0xfe51, 0x0301}, // dead_acute
{0xfe52, 0x0302}, // dead_circumflex
{0xfe53, 0x0303}, // dead_tilde
{0xfe54, 0x0304}, // dead_macron
{0xfe55, 0x0306}, // dead_breve
{0xfe56, 0x0307}, // dead_abovedot
{0xfe57, 0x0308}, // dead_diaeresis
{0xfe58, 0x030a}, // dead_abovering
{0xfe59, 0x030b}, // dead_doubleacute
{0xfe5a, 0x030c}, // dead_caron
{0xfe5b, 0x0327}, // dead_cedilla
{0xfe5c, 0x0328}, // dead_ogonek
{0xfe5d, 0x0345}, // dead_iota
{0xfe5e, 0x3099}, // dead_voiced_sound
{0xfe5f, 0x309a}, // dead_semivoiced_sound
{0xff08, 0x0008}, // BackSpace /* back space, back char */
{0xff09, 0x0009}, // Tab
{0xff0a, 0x000a}, // Linefeed /* Linefeed, LF */
{0xff0b, 0x000b}, // Clear
{0xff0d, 0x000d}, // Return /* Return, enter */
{0xff13, 0x0013}, // Pause /* Pause, hold */
{0xff14, 0x0014}, // Scroll_Lock
{0xff15, 0x0015}, // Sys_Req
{0xff1b, 0x001b}, // Escape
{0xff80, 0x0032}, // KP_Space /* space */
{0xff89, 0x0009}, // KP_Tab
{0xff8d, 0x000d}, // KP_Enter /* enter */
{0xffaa, 0x002a}, // KP_Multiply
{0xffab, 0x002b}, // KP_Add
{0xffac, 0x002c}, // KP_Separator /* separator, often comma */
{0xffad, 0x002d}, // KP_Subtract
{0xffae, 0x002e}, // KP_Decimal
{0xffaf, 0x002f}, // KP_Divide
{0xffb0, 0x0030}, // KP_0
{0xffb1, 0x0031}, // KP_1
{0xffb2, 0x0032}, // KP_2
{0xffb3, 0x0033}, // KP_3
{0xffb4, 0x0034}, // KP_4
{0xffb5, 0x0035}, // KP_5
{0xffb6, 0x0036}, // KP_6
{0xffb7, 0x0037}, // KP_7
{0xffb8, 0x0038}, // KP_8
{0xffb9, 0x0039}, // KP_9
{0xffbd, 0x003d}, // KP_Equal /* equals */
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 */)
}