web: frontend using Bootstrap

This commit is contained in:
Vincent Bernat
2022-03-19 17:39:48 +01:00
parent de88cd92ae
commit a336370c05
41 changed files with 1435 additions and 504 deletions

View File

@@ -1 +1,2 @@
Dockerfile Dockerfile
node_modules/

4
.gitignore vendored
View File

@@ -1,4 +1,6 @@
/bin/ /bin/
/test/ /test/
/flow/decoder/flow*.pb.go /flow/decoder/flow*.pb.go
/web/data
/web/data/node_modules/
/web/data/assets/generated/

View File

@@ -32,9 +32,8 @@ run tests:
alias: clickhouse alias: clickhouse
script: script:
- export GOMODCACHE=$PWD/.go-cache - export GOMODCACHE=$PWD/.go-cache
- time apk add --no-cache git make gcc musl-dev protoc shared-mime-info - time apk add --no-cache git make gcc musl-dev protoc shared-mime-info yarn
- time go mod download - time go mod download
- mkdir -p web/data && touch web/data/install.html # don't build web data
- time make test - time make test
- time make test-race || make test-race - time make test-race || make test-race
- time make test-coverage || make test-coverage - time make test-coverage || make test-coverage

View File

@@ -1,19 +1,11 @@
FROM squidfunk/mkdocs-material:8.2.5 AS documentation
COPY mkdocs.yml /docs/
COPY docs /docs/docs/
RUN mkdocs build --strict --site-dir /output
FROM golang:1.18-alpine AS build FROM golang:1.18-alpine AS build
RUN apk add --no-cache git make gcc musl-dev protoc shared-mime-info RUN apk add --no-cache git make gcc musl-dev protoc shared-mime-info yarn
WORKDIR /app WORKDIR /app
COPY go.mod ./ COPY go.mod ./
COPY go.sum ./ COPY go.sum ./
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN make clean RUN make clean && make test && make
COPY --from=documentation /output web/data/
RUN find web/data
RUN make test && make
# Do not use scratch, we use alpine to get an healthcheck # Do not use scratch, we use alpine to get an healthcheck
FROM alpine FROM alpine

View File

@@ -13,7 +13,7 @@ M = $(shell if [ "$$(tput colors 2> /dev/null || echo 0)" -ge 8 ]; then printf "
export GO111MODULE=on export GO111MODULE=on
GENERATED = flow/decoder/flow-1.pb.go web/data GENERATED = flow/decoder/flow-1.pb.go web/data/node_modules web/data/assets/generated
.PHONY: all .PHONY: all
all: fmt lint $(GENERATED) | $(BIN) ; $(info $(M) building executable) @ ## Build program binary all: fmt lint $(GENERATED) | $(BIN) ; $(info $(M) building executable) @ ## Build program binary
@@ -50,13 +50,14 @@ $(BIN)/protoc-gen-go: PACKAGE=google.golang.org/protobuf/cmd/protoc-gen-go
flow/decoder/%.pb.go: flow/data/schemas/%.proto | $(PROTOC_GEN_GO) ; $(info $(M) compiling protocol buffers definition) flow/decoder/%.pb.go: flow/data/schemas/%.proto | $(PROTOC_GEN_GO) ; $(info $(M) compiling protocol buffers definition)
$Q $(PROTOC) -I=. --plugin=$(PROTOC_GEN_GO) --go_out=. --go_opt=module=$(MODULE) $< $Q $(PROTOC) -I=. --plugin=$(PROTOC_GEN_GO) --go_out=. --go_opt=module=$(MODULE) $<
web/data: mkdocs.yml $(wildcard docs/*.md docs/assets/*) ; $(info $(M) build documentation) @ ## Build documentation web/data/node_modules: web/data/package.json web/data/yarn.lock ; $(info $(M) fetching node modules)
$Q rm -rf web/data $Q yarn install --frozen-lockfile --cwd web/data && touch $@
$Q mkdir -p web/data web/data/assets/generated: web/data/node_modules Makefile ; $(info $(M) copying static assets)
$Q docker run --rm -it --user=$(shell id -u):$(shell id -g) \ $Q rm -rf $@ && mkdir -p $@/stylesheets $@/javascript $@/fonts
-v $(CURDIR):/docs:ro \ $Q cp web/data/node_modules/@mdi/font/fonts/materialdesignicons-webfont.woff* $@/fonts/.
-v $(CURDIR)/web/data:/output:rw \ $Q cp web/data/node_modules/@mdi/font/css/materialdesignicons.min.css $@/stylesheets/.
squidfunk/mkdocs-material:8.2.5 build --strict --site-dir /output $Q cp web/data/node_modules/bootstrap/dist/css/bootstrap.min.css $@/stylesheets/.
$Q cp web/data/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js $@/javascript/.
# These files are versioned in Git, but we may want to update them. # These files are versioned in Git, but we may want to update them.
clickhouse/data/protocols.csv: clickhouse/data/protocols.csv:

1
docs Symbolic link
View File

@@ -0,0 +1 @@
web/data/docs

View File

@@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="287.20584"
height="76.251686"
viewBox="0 0 75.989878 20.174926"
version="1.1"
id="svg5"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="akvorado.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
fit-margin-top="10"
lock-margins="true"
fit-margin-left="10"
fit-margin-right="10"
fit-margin-bottom="10"
units="px"
inkscape:zoom="1"
inkscape:cx="190"
inkscape:cy="88.5"
inkscape:window-width="1894"
inkscape:window-height="1034"
inkscape:window-x="1930"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-30.07189,-113.10053)">
<path
d="m 32.717723,126.65779 h 2.035069 l 0.923719,-2.33816 h 4.430963 l 0.952586,2.33816 h 2.078367 L 38.73633,116.43915 h -1.573209 z m 3.579412,-3.89694 1.602074,-4.15673 1.573209,4.15673 z"
id="path34840"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
d="m 43.862763,126.65779 h 1.731972 v -3.53612 h 0.02886 l 2.756723,3.53612 h 2.294864 l -3.16085,-3.78148 2.97322,-3.14641 H 48.26486 l -2.670125,2.87218 v -6.85572 h -1.731972 z"
id="path34842"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
d="m 53.246972,126.65779 h 1.847438 l 2.727857,-6.92789 h -1.775272 l -1.86187,4.84952 h -0.02886 L 52.308826,119.7299 H 50.41809 Z"
id="path34844"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
d="m 58.243521,123.19384 c 0,2.17939 1.674239,3.63715 3.767042,3.63715 2.0928,0 3.767039,-1.45776 3.767039,-3.63715 0,-2.1794 -1.674239,-3.63714 -3.767039,-3.63714 -2.092803,0 -3.767042,1.45774 -3.767042,3.63714 z m 1.731972,0 c 0,-1.08248 0.764956,-2.07836 2.03507,-2.07836 1.270111,0 2.035067,0.99588 2.035067,2.07836 0,1.08249 -0.764956,2.07837 -2.035067,2.07837 -1.270114,0 -2.03507,-0.99588 -2.03507,-2.07837 z"
id="path34846"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
d="m 67.137003,126.65779 h 1.731974 v -3.70932 c 0,-0.37525 0.230928,-1.74639 1.86187,-1.74639 0.274229,0 0.548457,0.0578 0.83712,0.12989 v -1.67425 c -0.202064,-0.0578 -0.404127,-0.10109 -0.620624,-0.10109 -0.909285,0 -1.674241,0.4763 -2.049501,1.27011 h -0.02886 v -1.09691 h -1.731974 z"
id="path34848"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
d="m 76.824322,126.65779 h 1.558777 v -3.98354 c 0,-0.98146 0,-3.11755 -2.958788,-3.11755 -1.096916,0 -2.179399,0.33196 -2.944353,1.11135 l 0.909286,0.90928 c 0.461858,-0.43299 1.125781,-0.72165 1.847438,-0.72165 0.923719,0 1.58764,0.44742 1.58764,1.29898 v 0.18762 h -0.432993 c -1.731972,0 -4.358798,0.15871 -4.358798,2.41034 0,1.37114 1.241248,2.07837 2.525794,2.07837 0.923719,0 1.731974,-0.3464 2.222698,-1.12579 h 0.0433 z m -0.101037,-2.71344 c 0,0.96703 -0.562891,1.58766 -1.746406,1.58766 -0.562893,0 -1.212382,-0.27424 -1.212382,-0.90929 0,-0.99588 1.645375,-1.06806 2.59796,-1.06806 h 0.360828 z"
id="path34850"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
d="m 85.472443,126.65779 h 1.645374 v -10.91143 h -1.731972 v 4.86395 h -0.0433 c -0.360829,-0.44742 -1.053618,-1.05361 -2.352598,-1.05361 -1.977335,0 -3.348481,1.58764 -3.348481,3.63714 0,2.04949 1.284548,3.63715 3.420647,3.63715 0.967019,0 1.876304,-0.37528 2.381462,-1.21238 h 0.02886 z m -4.099003,-3.46395 c 0,-1.08248 0.764955,-2.07836 2.035069,-2.07836 1.270113,0 2.035067,0.99588 2.035067,2.07836 0,1.08249 -0.764954,2.07837 -2.035067,2.07837 -1.270114,0 -2.035069,-0.99588 -2.035069,-2.07837 z"
id="path34852"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px" />
<path
id="path34854"
style="font-weight:bold;font-size:8.46667px;line-height:6.61458px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';letter-spacing:-0.150813px;word-spacing:0px;fill:#008aff;stroke-width:0.264583px"
d="m 92.244323,119.55684 c -2.0928,0 -3.766841,1.45794 -3.766841,3.63735 0,2.17939 1.674041,3.63646 3.766841,3.63646 2.092804,0 3.766846,-1.45707 3.766846,-3.63646 0,-2.17941 -1.674042,-3.63735 -3.766846,-3.63735 z m -0.384083,0.0335 c 0.318201,-0.0372 0.518798,0.85445 0.738217,1.55219 0.526254,0.0829 0.944412,0.35044 1.232416,0.71796 0.715832,-0.17418 1.605845,-0.47974 1.741593,-0.18412 0.138733,0.30212 -0.710294,0.79319 -1.311699,1.22978 0.01204,0.0947 0.01849,0.19133 0.01849,0.28806 0,0.37252 -0.09104,0.73423 -0.261632,1.04918 0.386925,0.62868 0.958272,1.38709 0.717952,1.60857 -0.234799,0.21641 -0.918261,-0.38231 -1.504624,-0.81749 -0.280376,0.15043 -0.611345,0.23784 -0.986637,0.23784 -0.168719,0 -0.328056,-0.0181 -0.47834,-0.0511 -0.46623,0.55638 -0.984455,1.27876 -1.259726,1.12406 -0.273512,-0.1537 0.06847,-0.96252 0.301277,-1.64733 -0.352993,-0.35603 -0.560978,-0.84273 -0.593746,-1.35927 -0.677309,-0.27526 -1.547274,-0.54858 -1.484359,-0.86242 0.06243,-0.31143 0.957939,-0.23106 1.686093,-0.22288 0.212938,-0.45472 0.584672,-0.82467 1.086181,-1.00954 0.05038,-0.72468 0.04447,-1.6168 0.358537,-1.6535 z" />
<path
fill="#003f7f"
id="path2392"
d="m 90.773637,130.61285 c 2.096125,-0.14362 4.343482,0.11884 6.25831,-0.92926 2.886125,-1.62154 4.321033,-5.61671 2.748235,-8.60997 -1.615567,-2.8944 -5.438072,-4.11118 -8.521013,-3.09521 -1.440315,0.49783 -2.647179,1.64346 -3.17241,3.07869 0.03483,0.46971 0.429007,-0.54904 0.641262,-0.63717 0.938675,-1.13745 2.370283,-1.91164 3.870277,-1.80965 1.867469,0.0696 3.428769,1.52402 4.059414,3.21754 0.606814,1.4142 0.580868,3.25515 -0.5885,4.38002 -1.676811,1.76153 -3.979278,2.8234 -6.317816,3.38609 -1.057647,0.25736 -2.152346,0.29912 -3.228859,0.15233 -0.246286,-0.0152 -0.82219,-0.0779 -0.276216,0.11618 1.406516,0.65621 2.991595,0.82631 4.527316,0.75041 z"
style="fill:#5abdf6;fill-opacity:1;stroke-width:0.264582" />
<path
fill="#003f7f"
id="path2388"
d="m 96.844137,130.09685 c 1.818873,-0.0542 3.755343,0.004 5.394543,-0.9119 0.66322,-0.30119 1.10351,-0.97436 1.16389,-1.69324 0.1043,-1.23345 -0.42055,-2.4085 -0.92885,-3.50011 -0.72005,-1.48161 -1.64914,-2.85201 -2.663488,-4.14643 -0.431263,-0.0467 0.0677,0.57629 0.14909,0.76679 0.359398,0.60029 0.618008,1.25542 0.848048,1.91505 0.40259,1.20514 0.47062,2.56613 -0.0641,3.74323 -0.68801,1.74858 -2.166307,3.13289 -3.899103,3.82661 z"
style="fill:#5abdf6;fill-opacity:1;stroke-width:0.264582" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,26 +0,0 @@
/* Add more room for the logo and hide the title */
.md-header__button.md-logo {
margin: 0;
margin-left: inherit;
padding: 0;
padding-left: inherit;
}
.md-header__button.md-logo img, .md-header__button.md-logo svg {
height: 2.4rem;
width: initial;
}
.md-header__title {
visibility: hidden;
}
/* No footer */
.md-footer {
display: none;
}
/* Logo on the first page */
.akvorado-logo {
margin-left: auto;
margin-right: auto;
display: block;
}

View File

@@ -1,72 +0,0 @@
# Design
<figure markdown>
![General design](assets/images/design.svg){ width="500" }
<figcaption>General design for Akvorado</figcaption>
</figure>
## Big picture
The general design of *Akvorado* is the following:
- The exporters send flow to Akvorado. They don't need to be declared.
- The received flows are decoded then sent to the core component.
- For each flow, the core component query the GeoIP component and the
SNMP poller to get additional information, including country, AS
number, interface name, description and speed.
- The GeoIP component provides country and AS information for IP
addresses using Maxmind databases.
- The SNMP poller queries the exporters for host names, interface
names, interface descriptions and interface speeds. This information
is cached and updated from time to time.
- Once the core component has a complete flow, it pushes it to the
Kafka component.
- The Kafka component turns the flow into a binary representation
using *protocol buffers* and send the result into a Kafka topic.
The remaining steps are outside of *Akvorado* control:
- A ClickHouse database subscribe to the Kafka topic to receive and
process the flows.
- A graphing tool like Grafana queries this database to build various
dashboards.
## Flow representation
The flow representation is encoded in a versioned `flow-*.proto` file.
Any information that could change with time is embedded in the flow.
This includes for example interface names and speeds, as well. This
ensures that older data are not processed using incorrect mappings.
Each time the schema changes, we issue a new `flow-*.proto` file,
update the schema version and a new Kafka topic will be used. This
ensures we do not mix different schemas in a single topic.
## Future plans
In the future, we may:
- Add more information to the landing page, including some basic statistics.
- Automatically build dashboards for Grafana.[^grafana]
- Builds dashboards with [D3.js][].[^d3js]
- Buffer message to disks instead of blocking (when sending to Kafka)
or dropping (when querying the SNMP poller). We could probable just
have a system service running tcpdump dumping packets to a directory
and use that as input. This would be allow *Akvorado* to block from
end-to-end instead of trying to be realtime.
- Collect routes by integrating GoBGP. This is low priority if we
consider information from Maxmind good enough for our use.
[^grafana]: The templating system in Grafana is quite limited.
Notably, it is difficult to build different query depending on the
input fields. Grafana supports scripted dashboard, but it does not
seem to be possible to have a function build the query string.
[^d3js]: There is a [gallery][] containing many interesting examples,
including [stacked area charts][], [small multiple charts][] and
[Sankey diagrams][].
[expression language]: https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md
[D3.js]: https://d3js.org/
[gallery]: https://www.d3-graph-gallery.com/
[stacked area charts]: https://www.d3-graph-gallery.com/stackedarea.html
[small multiple charts]: https://www.d3-graph-gallery.com/graph/area_smallmultiple.html
[Sankey diagrams]: https://www.d3-graph-gallery.com/graph/sankey_basic.html

View File

@@ -1,27 +0,0 @@
---
hide:
- navigation
- toc
---
# Akvorado { style=display:none }
![](assets/images/akvorado.svg){ .akvorado-logo }
*Akvorado* is a flow collector, hydrater and exporter. It receives
flows, adds some data like interface names and geo information, and
exports them to Kafka. [Akvorado][] means "water wheel" in Esperanto.
[Akvorado]: https://eo.wikipedia.org/wiki/Akvorado
<!-- The documentation is expected to be browsed inside Akvorado itself -->
The embedded HTTP server serves the following endpoints:
- [`/api/v0/metrics`](/api/v0/metrics){ target=http }: Prometheus metrics
- [`/api/v0/version`](/api/v0/version){ target=http }: *Akvorado* version
- [`/api/v0/healthcheck`](/api/v0/healthcheck){ target=http }: are we alive?
- [`/api/v0/flows`](/api/v0/flows?limit=1){ target=http }: next available flow
- [`/api/v0/grafana`](/api/v0/grafana): Grafana web interface (if configured)
<iframe name="http" style="width: 100%; height: 200px; border: 0; background-color: #1111"></iframe>

View File

@@ -1,36 +0,0 @@
# Usage
*Akvorado* uses a subcommand system. Each subcommand comes with its
own set of options. It is possible to get help using `akvorado
--help`.
## version
`akvorado version` displays the version.
## serve
`akvorado serve` starts *Akvorado* itself, allowing it to receive and
process flows. When started from a TTY, it will display logs in a
fancy way. Without a TTY, logs are output using JSON.
The `--config` options allows to provide a configuration file in YAML
format. See the [configuration section](configuration.md) for more
information on this file.
The `--check` option will check if the provided configuration is
correct and stops here. The `--dump` option will dump the parsed
configuration, along with the default values. It should be combined
with `--check` if you don't want *Akvorado* to start.
### Exposed HTTP endpoints
The embedded HTTP server contains the endpoints listed on the [home
page](index.md). The [`/api/v0/flows`](/api/v0/flows?limit=1)
continously printed flows sent to Kafka (using [ndjson]()). It also
accepts a `limit` argument to stops after emitting the specified
number of flows. This endpoint should not be used for anything else
other than debug: it can skips some flows and if there are several
users, flows will be dispatched between them.
[ndjson]: http://ndjson.org/

View File

@@ -121,9 +121,7 @@ func (c *Component) Start() error {
} }
c.t.Go(func() error { c.t.Go(func() error {
errLogger := c.r.Sample(reporter.BurstSampler(10*time.Second, 1)) errLogger := c.r.Sample(reporter.BurstSampler(10*time.Second, 1))
defer func() { defer watcher.Close()
watcher.Close()
}()
for { for {
// Watch both for errors and events in the // Watch both for errors and events in the

11
go.mod
View File

@@ -4,6 +4,7 @@ go 1.17
require ( require (
github.com/ClickHouse/clickhouse-go/v2 v2.0.12 github.com/ClickHouse/clickhouse-go/v2 v2.0.12
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/Shopify/sarama v1.32.1-0.20220321223103-27b8f1b5973b github.com/Shopify/sarama v1.32.1-0.20220321223103-27b8f1b5973b
github.com/antonmedv/expr v1.9.0 github.com/antonmedv/expr v1.9.0
github.com/benbjohnson/clock v1.3.0 github.com/benbjohnson/clock v1.3.0
@@ -25,6 +26,8 @@ require (
github.com/slayercat/GoSNMPServer v0.1.2 github.com/slayercat/GoSNMPServer v0.1.2
github.com/slayercat/gosnmp v1.24.0 github.com/slayercat/gosnmp v1.24.0
github.com/spf13/cobra v1.3.0 github.com/spf13/cobra v1.3.0
github.com/yuin/goldmark v1.4.5
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
go.uber.org/atomic v1.7.0 go.uber.org/atomic v1.7.0
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
@@ -33,10 +36,14 @@ require (
) )
require ( require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect
@@ -46,6 +53,8 @@ require (
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
@@ -54,6 +63,8 @@ require (
github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/klauspost/compress v1.15.1 // indirect github.com/klauspost/compress v1.15.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // indirect github.com/oschwald/maxminddb-golang v1.8.0 // indirect
github.com/paulmach/orb v0.4.0 // indirect github.com/paulmach/orb v0.4.0 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect

21
go.sum
View File

@@ -77,6 +77,12 @@ github.com/ClickHouse/clickhouse-go/v2 v2.0.12 h1:Nbl/NZwoM6LGJm7smNBgvtdr/rxjlI
github.com/ClickHouse/clickhouse-go/v2 v2.0.12/go.mod h1:u4RoNQLLM2W6hNSPYrIESLJqaWSInZVmfM+MlaAhXcg= github.com/ClickHouse/clickhouse-go/v2 v2.0.12/go.mod h1:u4RoNQLLM2W6hNSPYrIESLJqaWSInZVmfM+MlaAhXcg=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@@ -111,6 +117,8 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrU
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -337,6 +345,8 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dhui/dktest v0.3.7/go.mod h1:nYMOkafiA07WchSwKnKFUSbGMb2hMm5DrCGiXYG6gwM= github.com/dhui/dktest v0.3.7/go.mod h1:nYMOkafiA07WchSwKnKFUSbGMb2hMm5DrCGiXYG6gwM=
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/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@@ -633,6 +643,8 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -640,6 +652,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -816,6 +829,8 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.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/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -824,6 +839,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM= github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
@@ -1104,6 +1121,10 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.5 h1:4OEQwtW2uLXjEdgnGM3Vg652Pq37X7NOIRzFWb3BzIc=
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg=
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=

View File

@@ -1,66 +0,0 @@
---
site_name: Akvorado
site_dir: web/data
strict: true
use_directory_urls: false
theme:
name: material
language: en
features:
- content.code.annotate
- navigation.indexes
- navigation.sections
- navigation.tabs
- navigation.top
- navigation.tracking
- search.highlight
- search.share
- search.suggest
- toc.integrate
palette:
- scheme: default
primary: white
accent: "#008affff"
toggle:
icon: material/toggle-switch-off-outline
name: Switch to dark mode
- scheme: slate
primary: black
accent: "#008affff"
toggle:
icon: material/toggle-switch
name: Switch to light mode
font:
text: Montserrat
code: Roboto Mono
logo: assets/images/akvorado.svg
extra_css:
- assets/stylesheets/extra.css
plugins:
- search
markdown_extensions:
- abbr
- admonition
- footnotes
- tables
- attr_list
- md_in_html
- toc:
permalink: true
- pymdownx.snippets
- pymdownx.highlight
- pymdownx.superfences
nav:
- Home: index.md
- Documentation:
Design: design.md
Installation: install.md
Configuration: configuration.md
Usage: usage.md
Integration: integration.md
Troubleshooting: troubleshooting.md
Internals: internals.md

39
web/assets.go Normal file
View File

@@ -0,0 +1,39 @@
package web
import (
"embed"
"errors"
"fmt"
"io/fs"
"net/http"
"path"
"strings"
)
//go:embed data/assets/generated data/assets/images
var embeddedAssets embed.FS
func (c *Component) assetsHandlerFunc(w http.ResponseWriter, req *http.Request) {
assets := c.embedOrLiveFS(embeddedAssets, "data/assets")
rpath := strings.TrimPrefix(req.URL.Path, "/assets/")
rpath = strings.Trim(rpath, "/")
for _, p := range []string{
fmt.Sprintf("%s", rpath),
fmt.Sprintf("generated/%s", rpath),
} {
f, err := http.FS(assets).Open(p)
if errors.Is(err, fs.ErrNotExist) {
continue
}
st, err := f.Stat()
if err != nil || st.IsDir() {
continue
}
http.ServeContent(w, req, path.Base(rpath), st.ModTime(), f)
f.Close()
return
}
http.Error(w, "Asset not found.", http.StatusNotFound)
}

43
web/assets_test.go Normal file
View File

@@ -0,0 +1,43 @@
package web
import (
"fmt"
netHTTP "net/http"
"testing"
"akvorado/http"
"akvorado/reporter"
)
func TestServeAssets(t *testing.T) {
for _, live := range []bool{false, true} {
for _, f := range []string{"images/akvorado.svg", "javascript/bootstrap.bundle.min.js"} {
var name string
switch live {
case true:
name = fmt.Sprintf("livefs-%s", f)
case false:
name = fmt.Sprintf("embeddedfs-%s", f)
}
t.Run(name, func(t *testing.T) {
r := reporter.NewMock(t)
h := http.NewMock(t, r)
_, err := New(r, Configuration{
ServeLiveFS: live,
}, Dependencies{HTTP: h})
if err != nil {
t.Fatalf("New() error:\n%+v", err)
}
resp, err := netHTTP.Get(fmt.Sprintf("http://%s/assets/%s", h.Address, f))
if err != nil {
t.Fatalf("GET /assets/%s:\n%+v", f, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Errorf("GET /assets/%s: got status code %d, not 200", f, resp.StatusCode)
}
})
}
}
}

View File

@@ -0,0 +1,440 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="204.24007"
height="206.63962"
viewBox="0 0 54.038518 54.673401"
version="1.1"
id="svg5"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="akvorado.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
fit-margin-top="10"
lock-margins="true"
fit-margin-left="10"
fit-margin-right="10"
fit-margin-bottom="10"
units="px"
inkscape:zoom="1.4142136"
inkscape:cx="130.81475"
inkscape:cy="78.135299"
inkscape:window-width="1894"
inkscape:window-height="1034"
inkscape:window-x="10"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(176.00828,-43.582565)">
<g
id="g26332"
transform="rotate(113.44554,-84.793189,47.315492)">
<g
id="g16200"
transform="matrix(-1,0,0,1,-186.83264,26.24814)">
<g
id="g16196"
transform="rotate(6.5216549,-636.60239,-1485.0258)" />
<path
id="path16198"
style="color:#000000;fill:#008aff;stroke-width:1;-inkscape-stroke:none"
d="m -154.12845,45.881077 c -11.12106,2.528351 -19.4815,12.521232 -19.4815,24.381458 0,13.754989 11.24503,25.000024 25.00003,25.000024 8.80938,0 16.58906,-4.612241 21.04471,-11.542448 0.0339,-0.308901 -7.10547,-5.044988 -7.34219,-4.770768 -2.86099,4.528427 -7.9085,7.51427 -13.70252,7.51427 -8.99913,0 -16.2016,-7.201958 -16.2016,-16.201078 0,-7.787643 5.39413,-14.226808 12.6783,-15.819705 0,0 -1.64211,-8.615618 -1.99523,-8.561753 z"
sodipodi:nodetypes="cssccsscc" />
</g>
<g
id="g26233">
<path
d="m -54.870647,105.9471 q 0.07094,0.12173 0.07925,0.25119 0.0059,0.13086 -0.05261,0.26089 -0.05991,0.12764 -0.184249,0.25446 -0.125731,0.12443 -0.319069,0.23711 -0.193338,0.11267 -0.361195,0.15933 -0.169247,0.0443 -0.30745,0.0321 -0.141981,-0.0132 -0.248142,-0.0856 -0.108547,-0.071 -0.17949,-0.19277 -0.07094,-0.12173 -0.07924,-0.25119 -0.01069,-0.12807 0.04922,-0.25572 0.05613,-0.12864 0.179475,-0.25168 0.121953,-0.12543 0.315291,-0.2381 0.193338,-0.11268 0.364973,-0.15834 0.170243,-0.0481 0.312223,-0.0349 0.14059,0.0108 0.251525,0.0804 0.108548,0.071 0.179491,0.19277 z m -0.272106,0.15858 q -0.02643,-0.0454 -0.07016,-0.071 -0.04613,-0.0243 -0.122491,-0.0182 -0.07637,0.006 -0.18496,0.0502 -0.109986,0.0417 -0.265134,0.13214 -0.155149,0.0904 -0.243274,0.16415 -0.0919,0.0727 -0.130109,0.13338 -0.04059,0.062 -0.03982,0.11274 7.75e-4,0.0507 0.0272,0.0961 0.02504,0.043 0.06877,0.0686 0.04374,0.0257 0.117716,0.0209 0.07159,-0.003 0.181578,-0.0451 0.1076,-0.0403 0.262748,-0.13074 0.155147,-0.0904 0.24566,-0.16555 0.09051,-0.0751 0.133492,-0.13855 0.04298,-0.0634 0.0446,-0.11552 -7.74e-4,-0.0507 -0.02581,-0.0937 z"
id="path24447"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.647108,105.3025 -0.166399,-0.34301 -0.912221,0.44252 0.143489,0.29579 -0.22619,0.10973 q -0.08756,-0.1172 -0.165765,-0.1898 -0.0782,-0.0726 -0.168916,-0.13299 l -0.130225,-0.26845 1.282577,-0.62219 -0.143489,-0.29579 0.295789,-0.14348 0.487139,1.00418 z"
id="path24449"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -56.140499,103.32921 q 0.05166,0.13109 0.04023,0.26031 -0.014,0.13023 -0.09156,0.24989 -0.07857,0.11708 -0.220706,0.22358 -0.143146,0.10393 -0.351334,0.18598 -0.208189,0.082 -0.38118,0.10272 -0.174005,0.0181 -0.308761,-0.0149 -0.13834,-0.0346 -0.23229,-0.12225 -0.09652,-0.0867 -0.148183,-0.21775 -0.05166,-0.13109 -0.04023,-0.26031 0.0089,-0.12821 0.08743,-0.24529 0.07498,-0.11864 0.215565,-0.22156 0.139563,-0.10548 0.347751,-0.18753 0.208188,-0.0821 0.384763,-0.10117 0.175562,-0.0217 0.313902,0.0129 0.137326,0.032 0.236416,0.11765 0.09652,0.0867 0.148184,0.21776 z m -0.293006,0.11549 q -0.01924,-0.0488 -0.05858,-0.0808 -0.04191,-0.031 -0.118322,-0.0365 -0.07641,-0.006 -0.190439,0.0216 -0.115041,0.0246 -0.282105,0.0904 -0.167065,0.0658 -0.265353,0.12537 -0.101871,0.058 -0.14883,0.11211 -0.04953,0.0551 -0.05646,0.1054 -0.0069,0.0502 0.01232,0.0991 0.01823,0.0463 0.05758,0.0783 0.03934,0.032 0.113182,0.0386 0.07127,0.008 0.186311,-0.017 0.11247,-0.0235 0.279534,-0.0894 0.167065,-0.0658 0.267924,-0.12639 0.100858,-0.0605 0.152958,-0.1167 0.0521,-0.0562 0.06159,-0.10742 0.0069,-0.0502 -0.01131,-0.0965 z"
id="path24451"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -56.622202,101.95545 q 0.04151,0.13464 0.02026,0.26262 -0.0239,0.12878 -0.110359,0.24217 -0.08727,0.11074 -0.237121,0.20609 -0.150659,0.0927 -0.3645,0.15863 -0.213843,0.0659 -0.387907,0.0733 -0.174878,0.005 -0.306723,-0.0384 -0.1353,-0.045 -0.222285,-0.13962 -0.08963,-0.0938 -0.131136,-0.22843 -0.04151,-0.13464 -0.02026,-0.26261 0.01861,-0.12716 0.105892,-0.23791 0.08382,-0.11257 0.231842,-0.20446 0.147205,-0.0945 0.361046,-0.16046 0.213842,-0.0659 0.391361,-0.0715 0.176704,-0.008 0.312003,0.0368 0.134485,0.0424 0.22675,0.13535 0.08963,0.0938 0.131137,0.22843 z m -0.300963,0.0928 q -0.01547,-0.0502 -0.05225,-0.0851 -0.03943,-0.0341 -0.115192,-0.0454 -0.07576,-0.0113 -0.191532,0.007 -0.116579,0.0157 -0.28818,0.0686 -0.171602,0.0529 -0.274145,0.10476 -0.105997,0.05 -0.156951,0.10042 -0.0536,0.0512 -0.06433,0.10078 -0.01074,0.0496 0.0047,0.0997 0.01465,0.0475 0.05144,0.0824 0.03678,0.0349 0.109911,0.0471 0.07049,0.013 0.187066,-0.003 0.113939,-0.0149 0.285541,-0.0678 0.171601,-0.0529 0.276785,-0.10557 0.105183,-0.0527 0.161417,-0.10469 0.05623,-0.052 0.06961,-0.10241 0.01073,-0.0496 -0.0039,-0.0971 z"
id="path24453"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.232258,101.15157 -0.0842,-0.37183 -0.988853,0.22393 0.07261,0.32064 -0.245193,0.0555 q -0.05867,-0.13401 -0.11836,-0.22247 -0.05969,-0.0884 -0.134322,-0.16786 l -0.0659,-0.291 1.390323,-0.31484 -0.07261,-0.32064 0.320636,-0.07261 0.246506,1.08854 z"
id="path24455"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.544603,99.700937 -0.05569,-0.377157 -1.003017,0.148091 0.04801,0.32523 -0.248705,0.03672 q -0.04831,-0.138081 -0.101101,-0.23082 -0.05279,-0.09274 -0.12117,-0.177592 l -0.04358,-0.295165 1.410236,-0.208216 -0.04801,-0.32523 0.325228,-0.04802 0.163022,1.10414 z"
id="path24457"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.74578,98.230915 -0.02706,-0.380283 -1.011334,0.07195 0.02333,0.327926 -0.250768,0.01784 q -0.03775,-0.141335 -0.08339,-0.237795 -0.04564,-0.09646 -0.107416,-0.186232 l -0.02117,-0.297613 1.421931,-0.101161 -0.02333,-0.327926 0.327927,-0.02333 0.0792,1.113295 z"
id="path24459"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.47165,96.215169 q -5.26e-4,0.140894 -0.05898,0.256707 -0.06121,0.115804 -0.177551,0.19825 -0.116329,0.07968 -0.287788,0.126009 -0.171447,0.04356 -0.39522,0.04273 -0.223772,-8.36e-4 -0.392128,-0.04566 -0.168346,-0.0476 -0.281314,-0.128132 -0.115721,-0.08331 -0.17054,-0.199548 -0.05759,-0.116247 -0.05706,-0.257141 5.26e-4,-0.140894 0.05898,-0.256708 0.05569,-0.115824 0.172015,-0.195507 0.113577,-0.08245 0.282262,-0.12603 0.168696,-0.04634 0.392468,-0.04551 0.223773,8.35e-4 0.394881,0.04844 0.171117,0.04484 0.286839,0.128152 0.115732,0.08055 0.176076,0.196807 0.05759,0.116246 0.05705,0.257141 z m -0.31494,-0.0011 q 1.96e-4,-0.05249 -0.0245,-0.09679 -0.02746,-0.04431 -0.0964,-0.07771 -0.06894,-0.03341 -0.18491,-0.05042 -0.115959,-0.01977 -0.295529,-0.02044 -0.179571,-6.7e-4 -0.292911,0.01825 -0.116092,0.01614 -0.179756,0.04906 -0.06643,0.03291 -0.09146,0.07701 -0.02503,0.0441 -0.02523,0.0966 -1.85e-4,0.04973 0.02451,0.09402 0.0247,0.0443 0.09088,0.0777 0.06342,0.03339 0.179375,0.05316 0.113195,0.01976 0.292767,0.02043 0.17957,6.7e-4 0.295673,-0.01824 0.116102,-0.0189 0.185292,-0.0518 0.06918,-0.03289 0.09698,-0.077 0.02503,-0.04411 0.02521,-0.09383 z"
id="path24461"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.814781,95.266467 0.02992,-0.380069 -1.010763,-0.07957 -0.02581,0.327741 -0.250625,-0.01973 q -0.01627,-0.145383 -0.04702,-0.247566 -0.03076,-0.102184 -0.07847,-0.20016 l 0.02342,-0.297447 1.421129,0.111877 0.0258,-0.327741 0.327741,0.0258 -0.08759,1.112667 z"
id="path24463"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.24302,93.314558 q -0.02164,0.139224 -0.09679,0.244968 -0.07788,0.10532 -0.205261,0.169396 -0.126959,0.06135 -0.303424,0.08145 -0.176041,0.01737 -0.39716,-0.017 -0.22112,-0.03437 -0.380853,-0.103929 -0.159309,-0.07229 -0.258929,-0.168852 -0.101925,-0.09972 -0.138702,-0.222857 -0.0395,-0.123565 -0.01787,-0.262788 0.02164,-0.139224 0.09679,-0.244968 0.07242,-0.106169 0.199376,-0.167514 0.124654,-0.0645 0.297965,-0.0823 0.173735,-0.02052 0.394854,0.01385 0.22112,0.03437 0.383158,0.107082 0.162464,0.06998 0.264389,0.169701 0.10235,0.09699 0.144586,0.220977 0.0395,0.123564 0.01787,0.262788 z m -0.311205,-0.04837 q 0.008,-0.05186 -0.0097,-0.09936 -0.02051,-0.04792 -0.08366,-0.09129 -0.06316,-0.04337 -0.175263,-0.07756 -0.111685,-0.03693 -0.289127,-0.0645 -0.177441,-0.02758 -0.292335,-0.02587 -0.117201,-0.0014 -0.185079,0.02156 -0.07061,0.02258 -0.101967,0.06243 -0.03136,0.03986 -0.03942,0.09173 -0.0076,0.04913 0.01014,0.09663 0.01778,0.0475 0.0782,0.09044 0.0577,0.04251 0.16938,0.07945 0.108954,0.0365 0.286395,0.06409 0.177442,0.02758 0.295067,0.0263 0.117624,-0.0013 0.190962,-0.02344 0.07334,-0.02215 0.107426,-0.06158 0.03136,-0.03986 0.039,-0.089 z"
id="path24465"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -57.43961,92.324693 0.08704,-0.371176 -0.987113,-0.231482 -0.07505,0.320071 -0.24476,-0.05739 q 0.0059,-0.146171 -0.009,-0.25183 -0.01495,-0.105659 -0.0473,-0.209722 l 0.06812,-0.290486 1.387875,0.325463 0.07505,-0.320072 0.320072,0.07505 -0.25482,1.086631 z"
id="path24467"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -56.578672,90.481856 q -0.04254,0.13432 -0.132881,0.22742 -0.09297,0.09226 -0.228614,0.136244 -0.134805,0.04134 -0.312276,0.0344 -0.176636,-0.0096 -0.389968,-0.07714 -0.21333,-0.06757 -0.360641,-0.160584 -0.146477,-0.09565 -0.230271,-0.206231 -0.08559,-0.114044 -0.103234,-0.241342 -0.02028,-0.128133 0.02226,-0.262453 0.04254,-0.134319 0.132881,-0.227419 0.08771,-0.09393 0.222512,-0.135279 0.133006,-0.04481 0.307008,-0.03607 0.174837,0.0061 0.388168,0.07367 0.213331,0.06757 0.362441,0.164051 0.149946,0.09386 0.235539,0.207898 0.08643,0.111411 0.109335,0.240378 0.02028,0.128132 -0.02226,0.262452 z m -0.300244,-0.09509 q 0.01585,-0.05004 0.0055,-0.09969 -0.01299,-0.05048 -0.06883,-0.102938 -0.05584,-0.05246 -0.161445,-0.103293 -0.104777,-0.05347 -0.275969,-0.107685 -0.171192,-0.05422 -0.285013,-0.06998 -0.115621,-0.01923 -0.186206,-0.0068 -0.07322,0.01158 -0.110268,0.04622 -0.03705,0.03463 -0.0529,0.08468 -0.01501,0.0474 -0.0046,0.09705 0.01036,0.04964 0.06356,0.101269 0.05057,0.05079 0.155344,0.104259 0.102143,0.05263 0.273335,0.106852 0.171192,0.05422 0.287647,0.07081 0.116455,0.01659 0.192307,0.0059 0.07585,-0.01075 0.115536,-0.04455 0.03705,-0.03463 0.05207,-0.08203 z"
id="path24469"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -56.622442,89.473598 0.142501,-0.353613 -0.940404,-0.378968 -0.122881,0.304926 -0.233179,-0.09397 q 0.02807,-0.143572 0.02937,-0.250274 0.0013,-0.106704 -0.01484,-0.214478 l 0.111521,-0.276739 1.322203,0.532827 0.12288,-0.304927 0.304926,0.122881 -0.417174,1.035212 z"
id="path24471"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.491209,87.783185 q -0.06246,0.126294 -0.165901,0.204582 -0.105917,0.07707 -0.246664,0.09992 -0.139524,0.02037 -0.313878,-0.01345 -0.173128,-0.03631 -0.373713,-0.135511 -0.200585,-0.0992 -0.332046,-0.213529 -0.130238,-0.116805 -0.196252,-0.238832 -0.06727,-0.125728 -0.06535,-0.254229 -5.66e-4,-0.129725 0.0619,-0.25602 0.06246,-0.126293 0.165901,-0.204581 0.100965,-0.07952 0.240488,-0.09989 0.138271,-0.02407 0.308924,0.011 0.171878,0.03261 0.372462,0.13181 0.200585,0.0992 0.333298,0.217231 0.133939,0.115552 0.201204,0.241281 0.06849,0.123251 0.07153,0.254201 5.66e-4,0.129726 -0.0619,0.25602 z m -0.282304,-0.139616 q 0.02327,-0.04705 0.02058,-0.09769 -0.0052,-0.05186 -0.05238,-0.112203 -0.04721,-0.06033 -0.14387,-0.12663 -0.09543,-0.06877 -0.256397,-0.148377 -0.160964,-0.0796 -0.271066,-0.112484 -0.111356,-0.03658 -0.183008,-0.03503 -0.07413,3.24e-4 -0.116011,0.02892 -0.04188,0.0286 -0.06515,0.07565 -0.02204,0.04458 -0.01935,0.09522 0.0027,0.05064 0.04743,0.109753 0.04226,0.05788 0.137694,0.126655 0.09296,0.06755 0.253921,0.147154 0.160962,0.0796 0.273542,0.113708 0.112579,0.03411 0.189185,0.03501 0.0766,8.75e-4 0.120963,-0.02647 0.04188,-0.0286 0.06393,-0.07317 z"
id="path24473"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.381354,86.78011 0.19446,-0.327923 -0.872085,-0.517149 -0.167686,0.282774 -0.216239,-0.12823 q 0.04951,-0.137657 0.06697,-0.24293 0.01746,-0.105272 0.01785,-0.214248 l 0.152186,-0.256635 1.226145,0.727109 0.167687,-0.282774 0.282774,0.167686 -0.569287,0.960007 z"
id="path24475"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -54.007223,85.280534 q -0.08083,0.115406 -0.194911,0.177163 -0.116346,0.06018 -0.258931,0.0615 -0.141,-9.63e-4 -0.308239,-0.06074 -0.165653,-0.06206 -0.348944,-0.190429 -0.18329,-0.128373 -0.295966,-0.261254 -0.11109,-0.135145 -0.157907,-0.265747 -0.04749,-0.134449 -0.02619,-0.261185 0.01904,-0.128321 0.09987,-0.243726 0.08083,-0.115405 0.194911,-0.177162 0.111821,-0.06334 0.25282,-0.06241 0.140323,-0.0029 0.303714,0.05757 0.164976,0.05821 0.348266,0.186581 0.18329,0.128373 0.296644,0.265102 0.114939,0.134466 0.162432,0.268915 0.04908,0.132187 0.0323,0.262093 -0.01904,0.128321 -0.09987,0.243726 z m -0.257963,-0.180673 q 0.03011,-0.043 0.0351,-0.09346 0.0027,-0.05206 -0.03482,-0.11883 -0.03755,-0.06677 -0.123084,-0.146916 -0.08394,-0.0824 -0.23103,-0.185419 -0.147085,-0.103015 -0.250955,-0.152155 -0.104549,-0.05298 -0.175613,-0.06228 -0.07332,-0.01088 -0.119049,0.01106 -0.04572,0.02194 -0.07583,0.06493 -0.02853,0.04073 -0.03352,0.0912 -0.005,0.05047 0.0303,0.115659 0.03303,0.0636 0.116973,0.14601 0.08169,0.08082 0.228767,0.183834 0.147085,0.103015 0.253218,0.153739 0.106133,0.05073 0.181722,0.06319 0.07559,0.01246 0.123576,-0.0079 0.04572,-0.02194 0.07425,-0.06268 z"
id="path24477"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -53.747234,84.305631 0.241643,-0.294883 -0.784219,-0.642632 -0.208374,0.254284 -0.194452,-0.159345 q 0.06968,-0.128626 0.102808,-0.230067 0.03312,-0.101441 0.04992,-0.209113 l 0.189112,-0.230779 1.102608,0.903537 0.208374,-0.254284 0.254283,0.208375 -0.70742,0.863281 z"
id="path24479"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -52.163065,83.029984 q -0.09726,0.101945 -0.219326,0.145852 -0.124069,0.042 -0.265233,0.02188 -0.139256,-0.02212 -0.295608,-0.106375 -0.154444,-0.08625 -0.316355,-0.240715 -0.161913,-0.154466 -0.253335,-0.302774 -0.08951,-0.150308 -0.116168,-0.286462 -0.02674,-0.14006 0.01337,-0.262154 0.03811,-0.124001 0.135372,-0.225945 0.09726,-0.101945 0.219326,-0.145853 0.120071,-0.04581 0.259328,-0.02369 0.139165,0.01822 0.291611,0.102561 0.154351,0.08234 0.316263,0.23681 0.161913,0.154465 0.253426,0.306679 0.09342,0.150216 0.120166,0.290276 0.02865,0.138061 -0.0074,0.263969 -0.03811,0.124001 -0.135372,0.225945 z m -0.227876,-0.217395 q 0.03623,-0.03798 0.04875,-0.08713 0.01052,-0.05105 -0.01657,-0.122715 -0.02709,-0.07166 -0.0996,-0.163747 -0.0706,-0.09409 -0.200535,-0.21804 -0.129929,-0.123953 -0.225232,-0.188147 -0.0954,-0.0681 -0.164255,-0.08797 -0.07086,-0.02178 -0.11936,-0.007 -0.0485,0.01482 -0.08474,0.0528 -0.03433,0.03598 -0.04684,0.08512 -0.01252,0.04914 0.01257,0.1189 0.02309,0.06785 0.0937,0.161933 0.06861,0.09218 0.198535,0.216132 0.12993,0.123954 0.227233,0.190054 0.0973,0.0661 0.170159,0.08979 0.07286,0.02369 0.123358,0.01078 0.0485,-0.01482 0.08283,-0.0508 z"
id="path24481"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -51.759575,82.105218 0.283179,-0.255259 -0.678842,-0.753093 -0.244191,0.220115 -0.168323,-0.186734 q 0.08821,-0.116705 0.136185,-0.212023 0.04798,-0.09532 0.08075,-0.199248 l 0.22162,-0.199768 0.954448,1.058844 0.24419,-0.220115 0.220116,0.244191 -0.829018,0.747281 z"
id="path24483"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -50.001843,81.081877 q -0.111463,0.08618 -0.238742,0.111259 -0.128971,0.02289 -0.265511,-0.0182 -0.134354,-0.04278 -0.276279,-0.149564 -0.139739,-0.108467 -0.276616,-0.285497 -0.136878,-0.17703 -0.204989,-0.337386 -0.06593,-0.162046 -0.07183,-0.300659 -0.0054,-0.142489 0.05259,-0.257173 0.05631,-0.11687 0.167769,-0.203053 0.111463,-0.08618 0.238744,-0.111259 0.12559,-0.02727 0.259944,0.01553 0.134851,0.03891 0.272899,0.145194 0.140236,0.104591 0.277114,0.281621 0.136876,0.17703 0.204493,0.341262 0.06981,0.162541 0.07521,0.30503 0.0076,0.140798 -0.04703,0.259854 -0.05631,0.11687 -0.167769,0.203053 z m -0.192641,-0.249153 q 0.04152,-0.0321 0.06129,-0.07882 0.01807,-0.04889 0.002,-0.12381 -0.01602,-0.07492 -0.07388,-0.17685 -0.05568,-0.103622 -0.165515,-0.245683 -0.109839,-0.14206 -0.194422,-0.219839 -0.08409,-0.08165 -0.14918,-0.111644 -0.06678,-0.03217 -0.11696,-0.02481 -0.05018,0.0073 -0.0917,0.03948 -0.03934,0.03041 -0.0591,0.07713 -0.01976,0.04671 -0.0054,0.119439 0.01264,0.07055 0.06832,0.174167 0.05398,0.101437 0.163824,0.243498 0.109841,0.142061 0.196113,0.222025 0.08627,0.07996 0.154745,0.114325 0.06848,0.03436 0.12034,0.02918 0.05018,-0.0073 0.08952,-0.03778 z"
id="path24485"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -49.463983,80.228173 0.318354,-0.209758 -0.557836,-0.846638 -0.274523,0.180879 -0.138319,-0.209929 q 0.10476,-0.102109 0.166529,-0.189125 0.06177,-0.08701 0.109804,-0.184834 l 0.249147,-0.164159 0.784314,1.190367 0.274523,-0.180879 0.180879,0.274523 -0.931993,0.614076 z"
id="path24487"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -47.572194,79.481117 q -0.123186,0.06839 -0.252792,0.07398 -0.130947,0.0031 -0.259727,-0.05804 -0.126365,-0.06256 -0.250562,-0.189522 -0.121782,-0.128301 -0.230394,-0.323949 -0.108613,-0.195649 -0.151761,-0.364444 -0.04073,-0.170135 -0.02567,-0.308053 0.01615,-0.141674 0.09077,-0.2463 0.07329,-0.107041 0.196475,-0.175426 0.123186,-0.06839 0.252792,-0.07398 0.128265,-0.008 0.25463,0.05455 0.127439,0.0588 0.24788,0.184691 0.122857,0.124545 0.231469,0.320193 0.108612,0.195648 0.150686,0.368199 0.04449,0.171211 0.02834,0.312884 -0.01373,0.140334 -0.08567,0.24979 -0.07329,0.107041 -0.196474,0.175428 z m -0.152862,-0.275358 q 0.04589,-0.02547 0.07247,-0.06867 0.02524,-0.04561 0.0207,-0.122084 -0.0045,-0.07647 -0.04636,-0.185969 -0.03941,-0.110833 -0.126568,-0.267836 -0.08716,-0.157001 -0.159043,-0.246646 -0.07081,-0.0934 -0.130635,-0.132866 -0.06116,-0.04188 -0.111881,-0.04216 -0.05071,-2.84e-4 -0.09661,0.02519 -0.04348,0.02414 -0.07005,0.06733 -0.02658,0.04319 -0.02338,0.117253 0.0018,0.07164 0.04126,0.182479 0.03807,0.108418 0.125228,0.26542 0.08716,0.157001 0.160383,0.249063 0.07323,0.09206 0.135733,0.136355 0.06251,0.0443 0.114562,0.04699 0.05072,2.85e-4 0.09419,-0.02385 z"
id="path24489"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -46.911516,78.718292 0.346425,-0.159179 -0.423321,-0.921289 -0.298728,0.137262 -0.104966,-0.228439 q 0.119002,-0.08509 0.193226,-0.161753 0.07422,-0.07667 0.136504,-0.166094 l 0.271116,-0.124574 0.595187,1.295329 0.298729,-0.137263 0.137262,0.29873 -1.014172,0.465999 z"
id="path24491"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -44.928329,78.266386 q -0.132137,0.0489 -0.261091,0.03476 -0.129912,-0.01673 -0.24791,-0.09679 -0.115406,-0.08101 -0.218898,-0.225351 -0.100901,-0.145297 -0.178564,-0.355162 -0.07766,-0.209865 -0.0947,-0.383253 -0.01444,-0.174347 0.02139,-0.308379 0.03746,-0.137584 0.127101,-0.229672 0.08868,-0.09468 0.220821,-0.143579 0.132137,-0.0489 0.261091,-0.03476 0.127995,0.01155 0.243402,0.09256 0.117039,0.07746 0.216981,0.22017 0.102532,0.141747 0.180195,0.351612 0.07766,0.209865 0.09306,0.386802 0.01799,0.175979 -0.01946,0.313562 -0.03487,0.136625 -0.122592,0.233895 -0.08868,0.09468 -0.220822,0.143578 z m -0.109303,-0.295366 q 0.04922,-0.01822 0.08205,-0.05688 0.03187,-0.04125 0.03899,-0.11753 0.0071,-0.07628 -0.0176,-0.19085 -0.02213,-0.115531 -0.08446,-0.283941 -0.06233,-0.16841 -0.119769,-0.267927 -0.05582,-0.103066 -0.10896,-0.151152 -0.0541,-0.05067 -0.104186,-0.05865 -0.05009,-0.008 -0.09931,0.01024 -0.04663,0.01726 -0.07946,0.05591 -0.03282,0.03866 -0.0409,0.112346 -0.009,0.0711 0.0131,0.186628 0.02118,0.11294 0.0835,0.281351 0.06233,0.16841 0.120728,0.270517 0.05841,0.102107 0.113468,0.155375 0.05506,0.05326 0.106104,0.06383 0.05008,0.008 0.09672,-0.0093 z"
id="path24493"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -44.159366,77.612721 0.366603,-0.104643 -0.27829,-0.974951 -0.316129,0.09024 -0.069,-0.241746 q 0.130557,-0.066 0.215576,-0.130485 0.08502,-0.06449 0.160177,-0.143403 l 0.286907,-0.0819 0.391274,1.370776 0.316128,-0.09024 0.09023,0.316129 -1.073243,0.306346 z"
id="path24495"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -42.130482,77.467765 q -0.138038,0.02823 -0.263341,-0.0053 -0.125855,-0.03629 -0.230303,-0.133369 -0.101741,-0.09763 -0.182072,-0.256027 -0.07763,-0.158954 -0.122461,-0.37819 -0.04484,-0.219237 -0.0353,-0.393197 0.01225,-0.174515 0.06805,-0.301539 0.05795,-0.130284 0.160557,-0.207665 0.102054,-0.08008 0.240092,-0.108318 0.138038,-0.02823 0.26334,0.0053 0.124749,0.03089 0.226489,0.128511 0.103894,0.09436 0.180966,0.250613 0.07978,0.155693 0.124614,0.37493 0.04484,0.219237 0.03314,0.396457 -0.009,0.176667 -0.06694,0.306952 -0.05524,0.12973 -0.156744,0.212525 -0.102054,0.08008 -0.240092,0.108317 z m -0.06311,-0.308555 q 0.05143,-0.01051 0.08975,-0.04374 0.03777,-0.03593 0.05641,-0.11023 0.01864,-0.07431 0.01163,-0.191308 -0.0043,-0.117553 -0.04028,-0.293483 -0.03598,-0.175931 -0.07762,-0.283028 -0.03949,-0.110357 -0.0847,-0.165967 -0.04577,-0.05832 -0.09405,-0.07382 -0.04829,-0.0155 -0.09971,-0.005 -0.04872,0.01 -0.08705,0.04318 -0.03832,0.03321 -0.05752,0.104818 -0.01975,0.0689 -0.01545,0.186447 0.0038,0.114847 0.03973,0.290777 0.03598,0.175931 0.07818,0.285734 0.0422,0.109804 0.08851,0.170827 0.04632,0.06102 0.09516,0.07924 0.04829,0.0155 0.09701,0.0055 z"
id="path24497"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -41.271219,76.938728 0.378235,-0.04781 -0.127148,-1.005888 -0.326159,0.04123 -0.03153,-0.249417 q 0.139059,-0.04543 0.232879,-0.09627 0.09382,-0.05084 0.18008,-0.11744 l 0.29601,-0.03741 0.178769,1.414272 0.326159,-0.04123 0.04123,0.326159 -1.107298,0.139966 z"
id="path24499"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -39.243851,77.102693 q -0.140716,0.0071 -0.259522,-0.04501 -0.118945,-0.05486 -0.207563,-0.166567 -0.08586,-0.111849 -0.141389,-0.28055 -0.05277,-0.168841 -0.06404,-0.392332 -0.01127,-0.22349 0.02439,-0.394023 0.03842,-0.170673 0.112729,-0.287833 0.07693,-0.120058 0.190032,-0.181084 0.112961,-0.06379 0.253678,-0.07088 0.140716,-0.0071 0.259522,0.04501 0.118667,0.04934 0.204524,0.161189 0.08848,0.108951 0.141113,0.275032 0.05539,0.165943 0.06666,0.389433 0.01127,0.22349 -0.02701,0.396922 -0.03552,0.173293 -0.112451,0.293351 -0.07417,0.119919 -0.186994,0.186463 -0.112963,0.06379 -0.253679,0.07088 z m -0.01586,-0.314543 q 0.05242,-0.0026 0.09532,-0.0297 0.04276,-0.02982 0.07239,-0.100465 0.02963,-0.07065 0.04034,-0.187367 0.01347,-0.116858 0.0045,-0.296202 -0.009,-0.179344 -0.03406,-0.291496 -0.02239,-0.115048 -0.05871,-0.176839 -0.03645,-0.06455 -0.08184,-0.08715 -0.0454,-0.0226 -0.09782,-0.01996 -0.04967,0.0025 -0.09256,0.02956 -0.0429,0.02706 -0.07267,0.09495 -0.02991,0.06513 -0.04338,0.181988 -0.01361,0.114099 -0.0045,0.293443 0.009,0.179344 0.0342,0.294254 0.02516,0.11491 0.06174,0.182219 0.03659,0.06731 0.08212,0.09267 0.0454,0.0226 0.09506,0.0201 z"
id="path24501"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -38.315022,76.708947 0.381134,0.0092 0.02456,-1.013593 -0.328658,-0.008 0.0061,-0.251327 q 0.144285,-0.02413 0.244648,-0.06039 0.100363,-0.03626 0.195604,-0.08922 l 0.298278,0.0073 -0.03453,1.425107 0.328658,0.008 -0.008,0.328658 -1.115782,-0.02704 z"
id="path24503"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -36.334845,77.173418 q -0.140201,-0.01397 -0.249909,-0.0832 -0.109435,-0.07198 -0.180404,-0.195657 -0.06822,-0.123402 -0.09797,-0.298498 -0.027,-0.174822 -0.0048,-0.397494 0.02218,-0.222673 0.08287,-0.385982 0.06344,-0.163035 0.15439,-0.267804 0.09397,-0.107244 0.21491,-0.150722 0.121212,-0.04623 0.261412,-0.03226 0.140201,0.01397 0.249909,0.0832 0.109983,0.06648 0.178202,0.189885 0.07124,0.120926 0.09852,0.292999 0.03003,0.172348 0.0079,0.395019 -0.02218,0.222672 -0.08589,0.388457 -0.06096,0.166059 -0.154938,0.273302 -0.09122,0.107518 -0.212709,0.156495 -0.12121,0.04622 -0.261412,0.03226 z m 0.03122,-0.31339 q 0.05223,0.0052 0.09868,-0.01516 0.04672,-0.02311 0.08656,-0.08855 0.03984,-0.06544 0.06783,-0.179257 0.03075,-0.113542 0.04855,-0.29223 0.0178,-0.178687 0.0098,-0.293314 -0.005,-0.117104 -0.03168,-0.183618 -0.02642,-0.06926 -0.06793,-0.09839 -0.04152,-0.02912 -0.09375,-0.03433 -0.04948,-0.0049 -0.09593,0.01543 -0.04645,0.02036 -0.08602,0.08305 -0.03929,0.05994 -0.07003,0.173484 -0.03047,0.110793 -0.04827,0.289481 -0.0178,0.178688 -0.01006,0.296064 0.0077,0.117377 0.03388,0.189389 0.02614,0.07201 0.06739,0.103885 0.04152,0.02912 0.091,0.03405 z"
id="path24505"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -35.357394,76.92267 0.375416,0.06642 0.176628,-0.998387 -0.323728,-0.05727 0.0438,-0.247556 q 0.146273,-0.0022 0.250946,-0.02294 0.104672,-0.02076 0.206792,-0.0588 l 0.293803,0.05198 -0.248338,1.403727 0.323727,0.05727 -0.05727,0.323727 -1.099042,-0.194435 z"
id="path24507"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -52.91967,104.76538 q 0.06214,0.10748 0.06907,0.22158 0.0048,0.11533 -0.04715,0.22973 -0.05318,0.11229 -0.163128,0.22366 -0.111168,0.10927 -0.281874,0.20797 -0.170707,0.0987 -0.318759,0.1393 -0.149263,0.0385 -0.271014,0.0273 -0.125069,-0.0121 -0.218396,-0.0762 -0.09543,-0.0629 -0.157576,-0.1704 -0.06214,-0.10749 -0.06907,-0.22159 -0.009,-0.11288 0.04415,-0.22518 0.04985,-0.11318 0.158912,-0.22123 0.107843,-0.11015 0.278549,-0.20885 0.170706,-0.0987 0.322085,-0.13842 0.15016,-0.0418 0.275229,-0.0298 0.12385,0.01 0.221391,0.0716 0.09544,0.0629 0.157577,0.17041 z m -0.240253,0.13891 q -0.02315,-0.04 -0.06162,-0.0628 -0.04057,-0.0215 -0.107881,-0.0164 -0.0673,0.005 -0.163137,0.0437 -0.09705,0.0364 -0.234031,0.11563 -0.136987,0.0792 -0.214864,0.14391 -0.0812,0.0638 -0.115053,0.11714 -0.03596,0.0545 -0.03543,0.0992 5.24e-4,0.0447 0.02368,0.0847 0.02193,0.0379 0.0604,0.0607 0.03846,0.0228 0.103665,0.0188 0.06309,-0.003 0.160144,-0.0391 0.09494,-0.0352 0.231924,-0.1144 0.136986,-0.0792 0.216972,-0.14513 0.07999,-0.0659 0.11805,-0.12168 0.03806,-0.0558 0.03965,-0.10166 -5.32e-4,-0.0447 -0.02248,-0.0826 z"
id="path24634"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -53.601817,104.19492 -0.145477,-0.30282 -0.805308,0.38688 0.12545,0.26112 -0.199681,0.0959 q -0.07676,-0.10356 -0.14543,-0.1678 -0.06867,-0.0642 -0.148398,-0.11776 l -0.113849,-0.23698 1.132258,-0.54395 -0.12545,-0.26112 0.261121,-0.12545 0.425884,0.88649 z"
id="path24636"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -54.155486,103.01036 -0.12203,-0.313 -0.832393,0.32453 0.105225,0.26991 -0.206398,0.0805 q -0.06866,-0.1091 -0.132249,-0.17837 -0.06359,-0.0693 -0.139014,-0.12871 l -0.0955,-0.24495 1.17034,-0.45628 -0.105225,-0.26991 0.269904,-0.10522 0.357245,0.91631 z"
id="path24638"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -54.617483,101.78729 -0.09805,-0.32132 -0.854517,0.26076 0.08455,0.27708 -0.211884,0.0647 q -0.06023,-0.11397 -0.118409,-0.18784 -0.05818,-0.0739 -0.128902,-0.13883 l -0.07673,-0.25147 1.201446,-0.36663 -0.08455,-0.27707 0.277078,-0.0846 0.287048,0.94067 z"
id="path24640"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -54.778583,100.00196 q 0.02727,0.12112 -1.55e-4,0.2321 -0.02979,0.11151 -0.113502,0.20521 -0.08424,0.0913 -0.222402,0.16485 -0.138692,0.0712 -0.331062,0.11446 -0.19237,0.0433 -0.345796,0.0379 -0.153961,-0.008 -0.266838,-0.0547 -0.115788,-0.0488 -0.18574,-0.13785 -0.07233,-0.0885 -0.0996,-0.20964 -0.02727,-0.12113 1.54e-4,-0.2321 0.02505,-0.11044 0.109287,-0.201771 0.08134,-0.09317 0.217652,-0.163781 0.135783,-0.07299 0.328153,-0.116297 0.19237,-0.04331 0.348705,-0.03608 0.155801,0.0049 0.271588,0.05365 0.115253,0.04642 0.189956,0.134404 0.07233,0.08852 0.09959,0.209645 z m -0.270737,0.061 q -0.01016,-0.0451 -0.04009,-0.07831 -0.0323,-0.03265 -0.09809,-0.04779 -0.06579,-0.01513 -0.168746,-0.0069 -0.10349,0.0058 -0.257862,0.04058 -0.154372,0.03475 -0.248001,0.0733 -0.09654,0.0367 -0.144749,0.0775 -0.05058,0.0413 -0.0634,0.0841 -0.01282,0.0428 -0.0027,0.0879 0.0096,0.0427 0.03955,0.0759 0.02993,0.0332 0.09334,0.0489 0.06104,0.0162 0.16453,0.0104 0.101114,-0.005 0.255487,-0.04 0.154371,-0.0348 0.250376,-0.0738 0.09601,-0.0391 0.148962,-0.081 0.05296,-0.0419 0.06815,-0.0852 0.01282,-0.0428 0.0032,-0.0855 z"
id="path24642"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.25995,99.254591 -0.04907,-0.332341 -0.883835,0.130505 0.04231,0.286585 -0.219152,0.03236 q -0.04258,-0.121673 -0.08909,-0.203393 -0.04652,-0.08172 -0.106775,-0.156488 l -0.0384,-0.260094 1.242668,-0.183486 -0.04232,-0.286584 0.286584,-0.04232 0.143659,0.972942 z"
id="path24644"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.437461,97.959236 -0.02382,-0.3351 -0.89117,0.06335 0.02054,0.288963 -0.220972,0.01571 q -0.03327,-0.12454 -0.07347,-0.209544 -0.04021,-0.085 -0.09464,-0.164109 l -0.01864,-0.262252 1.252979,-0.08907 -0.02054,-0.288962 0.288962,-0.02054 0.06973,0.981015 z"
id="path24646"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.195092,96.183378 q -6.42e-4,0.124151 -0.0523,0.226129 -0.05409,0.101966 -0.156707,0.174466 -0.102609,0.07006 -0.253753,0.110667 -0.15113,0.03817 -0.348313,0.03715 -0.197183,-0.001 -0.345476,-0.04074 -0.14828,-0.04215 -0.247723,-0.113267 -0.101863,-0.07356 -0.150021,-0.176055 -0.05059,-0.102508 -0.04994,-0.226663 6.42e-4,-0.12415 0.0523,-0.226128 0.04922,-0.101991 0.151825,-0.172057 0.100187,-0.07251 0.248885,-0.11069 0.148708,-0.04062 0.345892,-0.03959 0.197184,0.001 0.347898,0.04319 0.150727,0.03973 0.252592,0.113293 0.101876,0.07113 0.154901,0.173646 0.0506,0.102508 0.04994,0.226663 z m -0.277517,-0.0014 q 2.4e-4,-0.04625 -0.02144,-0.08532 -0.02414,-0.03908 -0.08485,-0.0686 -0.06071,-0.02952 -0.162874,-0.04466 -0.102155,-0.01757 -0.260388,-0.01839 -0.158233,-8.22e-4 -0.258129,0.0157 -0.102319,0.01407 -0.158456,0.04301 -0.05858,0.02891 -0.08069,0.06775 -0.02211,0.03884 -0.02235,0.08509 -2.27e-4,0.04382 0.02151,0.08287 0.02171,0.03907 0.07998,0.06858 0.05584,0.0295 0.157992,0.04707 0.09972,0.01756 0.257952,0.01838 0.158233,8.22e-4 0.260565,-0.01569 0.102337,-0.01648 0.16334,-0.04541 0.06101,-0.02889 0.08556,-0.06772 0.02211,-0.03884 0.02234,-0.08265 z"
id="path24648"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.139494,94.901737 q -0.01011,0.123741 -0.0694,0.22148 -0.06171,0.09754 -0.169561,0.162001 -0.107655,0.06203 -0.261456,0.09099 -0.153604,0.02652 -0.350133,0.01046 -0.196529,-0.01607 -0.341359,-0.06698 -0.144633,-0.05334 -0.23836,-0.131838 -0.09596,-0.08112 -0.136151,-0.186988 -0.04262,-0.106068 -0.03251,-0.229809 0.01011,-0.123741 0.0694,-0.221481 0.05685,-0.09794 0.16451,-0.15997 0.105427,-0.06466 0.256604,-0.09138 0.151378,-0.02914 0.347904,-0.01309 0.196531,0.01607 0.343588,0.06961 0.147258,0.05112 0.243213,0.132234 0.09615,0.07869 0.141202,0.184959 0.04262,0.106069 0.03251,0.22981 z m -0.276597,-0.02261 q 0.0038,-0.0461 -0.01488,-0.08671 -0.02109,-0.04081 -0.07937,-0.07488 -0.05828,-0.03407 -0.158992,-0.05696 -0.100516,-0.02531 -0.258225,-0.0382 -0.157709,-0.01289 -0.258575,-0.004 -0.103094,0.0062 -0.161282,0.03077 -0.06061,0.02435 -0.08562,0.0614 -0.02501,0.03703 -0.02878,0.08314 -0.0036,0.04367 0.01511,0.08428 0.01866,0.0406 0.07452,0.07448 0.05343,0.03368 0.153941,0.05899 0.09809,0.02511 0.255798,0.038 0.157709,0.01289 0.261002,0.0042 0.103291,-0.0087 0.166332,-0.0328 0.06303,-0.02416 0.09047,-0.061 0.02501,-0.03703 0.02858,-0.08071 z"
id="path24650"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -55.375445,94.044319 0.05283,-0.331765 -0.882301,-0.140502 -0.04556,0.286086 -0.218772,-0.03484 q -0.0041,-0.128842 -0.02401,-0.220749 -0.01986,-0.09191 -0.05494,-0.181303 l 0.04135,-0.259642 1.24051,0.197546 0.04556,-0.286087 0.286086,0.04556 -0.154667,0.971252 z"
id="path24652"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -54.736346,92.369814 q -0.0288,0.120766 -0.10225,0.208361 -0.07581,0.08703 -0.192213,0.134349 -0.115833,0.04495 -0.272247,0.05019 -0.15585,0.0029 -0.347655,-0.04287 -0.191805,-0.04575 -0.327214,-0.118084 -0.134845,-0.07471 -0.215554,-0.166533 -0.08251,-0.09476 -0.106149,-0.205508 -0.02601,-0.111315 0.0028,-0.232082 0.0288,-0.120766 0.102251,-0.208361 0.07108,-0.08816 0.186912,-0.13311 0.11403,-0.04788 0.26751,-0.05132 0.154048,-0.0058 0.345853,0.03994 0.191805,0.04575 0.329017,0.121017 0.137777,0.0729 0.220289,0.167662 0.08308,0.09239 0.111448,0.204271 0.02601,0.111314 -0.0028,0.232082 z m -0.269947,-0.06438 q 0.01073,-0.04499 -0.0015,-0.08796 -0.01464,-0.04353 -0.06706,-0.08607 -0.05242,-0.04253 -0.148488,-0.08046 -0.0955,-0.0403 -0.249419,-0.077 -0.153917,-0.03671 -0.254957,-0.04329 -0.102844,-0.0095 -0.164084,0.0059 -0.06361,0.01486 -0.09396,0.04766 -0.03035,0.0328 -0.04108,0.07779 -0.01016,0.04263 0.0021,0.08559 0.01229,0.04296 0.06233,0.08494 0.04769,0.0414 0.143187,0.0817 0.09313,0.03973 0.247051,0.07644 0.153917,0.03671 0.257326,0.04385 0.103408,0.0071 0.169384,-0.0071 0.06597,-0.01432 0.09869,-0.04653 0.03035,-0.0328 0.04051,-0.07543 z"
id="path24654"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -54.391514,91.134197 q -0.03788,0.118231 -0.11777,0.199999 -0.0822,0.08102 -0.201856,0.119373 -0.11891,0.03603 -0.27527,0.02938 -0.155619,-0.009 -0.343399,-0.06914 -0.18778,-0.06017 -0.317308,-0.14258 -0.128786,-0.08473 -0.202291,-0.182413 -0.07508,-0.100749 -0.09025,-0.212973 -0.01748,-0.112966 0.0204,-0.231197 0.03788,-0.118231 0.11777,-0.199999 0.07757,-0.08251 0.196477,-0.118536 0.117334,-0.03909 0.270635,-0.03087 0.154042,0.0059 0.341823,0.06608 0.187779,0.06017 0.318883,0.145641 0.131847,0.08315 0.206928,0.183898 0.07583,0.09843 0.09562,0.212141 0.01748,0.112967 -0.0204,0.231198 z m -0.264283,-0.08469 q 0.01412,-0.04404 0.0051,-0.08782 -0.0113,-0.04452 -0.06034,-0.09091 -0.04904,-0.04639 -0.141952,-0.0915 -0.09217,-0.04743 -0.242854,-0.09571 -0.150688,-0.04829 -0.250937,-0.06252 -0.101825,-0.01729 -0.164059,-0.0066 -0.06455,0.01 -0.0973,0.0404 -0.03275,0.0304 -0.04687,0.07446 -0.01337,0.04173 -0.0044,0.08551 0.009,0.04377 0.0557,0.08943 0.04441,0.04491 0.136574,0.09233 0.08985,0.04668 0.240536,0.09497 0.150687,0.04829 0.253254,0.06326 0.102567,0.01497 0.169438,0.0057 0.06687,-0.0092 0.10194,-0.03891 0.03275,-0.03041 0.04612,-0.07213 z"
id="path24656"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -53.954047,89.928252 q -0.04672,0.115027 -0.132562,0.190516 -0.0881,0.07458 -0.210307,0.103761 -0.1213,0.02691 -0.276706,0.0085 -0.154494,-0.02071 -0.337184,-0.09492 -0.18269,-0.0742 -0.305612,-0.166175 -0.122007,-0.09422 -0.187913,-0.197194 -0.06724,-0.10614 -0.07388,-0.219189 -0.0089,-0.113965 0.03784,-0.228993 0.04672,-0.115027 0.132562,-0.190516 0.08359,-0.0764 0.204879,-0.10334 0.11996,-0.03008 0.272196,-0.0103 0.153155,0.01754 0.335845,0.09175 0.182689,0.0742 0.306951,0.169347 0.125179,0.09288 0.192423,0.199025 0.06817,0.103884 0.0793,0.218767 0.0089,0.113966 -0.03783,0.228993 z m -0.257118,-0.104437 q 0.0174,-0.04285 0.01177,-0.08718 -0.0079,-0.04525 -0.05329,-0.09522 -0.04539,-0.04996 -0.134624,-0.101977 -0.08831,-0.05427 -0.234917,-0.113812 -0.146603,-0.05955 -0.245488,-0.08132 -0.100224,-0.02494 -0.163093,-0.01895 -0.06512,0.0051 -0.10008,0.03292 -0.03496,0.02784 -0.05236,0.07069 -0.01649,0.04059 -0.01085,0.08493 0.0056,0.04433 0.04878,0.09338 0.04089,0.04813 0.129197,0.102401 0.08606,0.05335 0.232662,0.112896 0.146603,0.05955 0.247744,0.08224 0.101141,0.02269 0.168519,0.01853 0.06738,-0.0042 0.104595,-0.03107 0.03496,-0.02784 0.05145,-0.06844 z"
id="path24658"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -53.426734,88.758785 q -0.05526,0.111174 -0.146556,0.179973 -0.09347,0.06772 -0.217536,0.0876 -0.12298,0.01771 -0.276555,-0.01242 -0.152491,-0.03231 -0.329063,-0.120083 -0.176571,-0.08778 -0.292206,-0.188757 -0.114551,-0.103161 -0.172501,-0.210807 -0.05904,-0.110911 -0.05711,-0.224142 -2.61e-4,-0.114313 0.055,-0.225487 0.05527,-0.111174 0.146558,-0.179973 0.08911,-0.06988 0.212091,-0.08759 0.121888,-0.02096 0.272197,0.01026 0.151396,0.02905 0.327967,0.116821 0.176571,0.08777 0.293302,0.19202 0.117815,0.102063 0.176861,0.212974 0.06013,0.108729 0.06257,0.224126 2.68e-4,0.114311 -0.055,0.225486 z m -0.248507,-0.123536 q 0.02059,-0.04142 0.01831,-0.08605 -0.0045,-0.04571 -0.04595,-0.09896 -0.0415,-0.05325 -0.126547,-0.111843 -0.08397,-0.06077 -0.225663,-0.131209 -0.141693,-0.07044 -0.238654,-0.09961 -0.09806,-0.03244 -0.161198,-0.0312 -0.06532,1.5e-4 -0.102286,0.02525 -0.03695,0.02513 -0.05754,0.06654 -0.01951,0.03924 -0.01722,0.08387 0.0023,0.04463 0.04159,0.0968 0.03713,0.05108 0.121103,0.111855 0.08179,0.05969 0.223483,0.130125 0.141693,0.07044 0.240834,0.100692 0.09914,0.03025 0.166641,0.03118 0.0675,9.32e-4 0.106645,-0.02308 0.03695,-0.02513 0.05646,-0.06436 z"
id="path24660"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -53.328328,87.87518 0.171772,-0.28871 -0.767801,-0.456814 -0.148122,0.248961 -0.190381,-0.11327 q 0.04381,-0.121237 0.05933,-0.213978 0.01552,-0.09274 0.016,-0.188769 l 0.134431,-0.225946 1.079523,0.642276 0.148122,-0.248959 0.24896,0.148122 -0.502869,0.845208 z"
id="path24662"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -52.648145,86.758677 0.193015,-0.274961 -0.731239,-0.513309 -0.166441,0.237104 -0.181315,-0.127277 q 0.05281,-0.117596 0.07526,-0.208906 0.02246,-0.09131 0.03016,-0.187027 l 0.151056,-0.215188 1.028117,0.721709 0.166441,-0.237104 0.237105,0.16644 -0.56506,0.80496 z"
id="path24664"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -51.339689,85.533893 q -0.07879,0.09595 -0.183177,0.142532 -0.106274,0.04503 -0.231638,0.0366 -0.123819,-0.01032 -0.26673,-0.07411 -0.141365,-0.06568 -0.293761,-0.190805 -0.152397,-0.125129 -0.242447,-0.249465 -0.08851,-0.126216 -0.120844,-0.244116 -0.03269,-0.121322 -0.0054,-0.231241 0.02537,-0.111462 0.104157,-0.207415 0.07879,-0.09595 0.183177,-0.142533 0.10251,-0.04813 0.22633,-0.0378 0.123483,0.0069 0.262967,0.07102 0.14103,0.06225 0.293426,0.187378 0.152396,0.125129 0.242784,0.252892 0.09193,0.125879 0.124611,0.247205 0.03424,0.119439 0.01073,0.232449 -0.02537,0.111462 -0.104157,0.207415 z m -0.214484,-0.176108 q 0.02935,-0.03574 0.03713,-0.07976 0.0059,-0.04555 -0.02263,-0.106741 -0.02849,-0.0612 -0.09825,-0.137367 -0.06821,-0.07805 -0.1905,-0.178464 -0.122292,-0.100412 -0.210245,-0.150579 -0.08829,-0.05359 -0.1501,-0.06655 -0.06369,-0.0145 -0.105341,0.0017 -0.04165,0.01618 -0.071,0.05195 -0.02781,0.03386 -0.03559,0.07788 -0.0078,0.04401 0.01884,0.103657 0.02474,0.05811 0.09295,0.136158 0.06632,0.07651 0.188618,0.17692 0.122294,0.100412 0.212128,0.152124 0.08983,0.05171 0.155407,0.06775 0.06558,0.01604 0.109105,0.0014 0.04165,-0.01618 0.06946,-0.05006 z"
id="path24666"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -51.045653,84.694802 0.232179,-0.242799 -0.645704,-0.617463 -0.200213,0.20937 -0.160107,-0.153104 q 0.06989,-0.108314 0.105831,-0.195207 0.03594,-0.08689 0.05795,-0.180363 l 0.181707,-0.190017 0.907857,0.86815 0.200213,-0.209371 0.209371,0.200213 -0.679714,0.710804 z"
id="path24668"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -49.567697,83.680955 q -0.09235,0.08298 -0.202578,0.113275 -0.111856,0.02847 -0.234507,0.0012 -0.120848,-0.02888 -0.252502,-0.113493 -0.129844,-0.08624 -0.261625,-0.232926 -0.131781,-0.146682 -0.20205,-0.283178 -0.06845,-0.138122 -0.08265,-0.259549 -0.014,-0.124865 0.02951,-0.229413 0.04189,-0.10636 0.134247,-0.189333 0.09235,-0.08298 0.202578,-0.113275 0.108588,-0.03215 0.229442,-0.0032 0.12103,0.02544 0.249248,0.109872 0.130028,0.0828 0.261809,0.229487 0.131781,0.146682 0.201865,0.286615 0.0719,0.138306 0.0859,0.263172 0.01581,0.123239 -0.02445,0.231408 -0.04189,0.106359 -0.134247,0.189333 z m -0.18547,-0.206442 q 0.0344,-0.03091 0.04874,-0.07324 0.0127,-0.04414 -0.0062,-0.108934 -0.01895,-0.06479 -0.07641,-0.150615 -0.05565,-0.08745 -0.161405,-0.205153 -0.105753,-0.117707 -0.185131,-0.180566 -0.0792,-0.06629 -0.138346,-0.08842 -0.06077,-0.02393 -0.104394,-0.0142 -0.04361,0.0097 -0.07802,0.04064 -0.0326,0.02928 -0.04692,0.07161 -0.01433,0.04233 0.003,0.105313 0.01567,0.06118 0.07134,0.14862 0.05403,0.08563 0.159779,0.203342 0.105752,0.117707 0.186757,0.182377 0.08101,0.06467 0.143411,0.09042 0.06241,0.02575 0.107647,0.01783 0.04362,-0.0097 0.07621,-0.03902 z"
id="path24670"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -49.150288,82.895762 0.266241,-0.204877 -0.544852,-0.708048 -0.229585,0.176669 -0.135099,-0.175565 q 0.08547,-0.0965 0.134146,-0.176949 0.04867,-0.08046 0.08457,-0.169519 l 0.208363,-0.160338 0.766059,0.995513 0.229585,-0.176669 0.176669,0.229585 -0.779432,0.599783 z"
id="path24672"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -48.105562,82.10928 0.28108,-0.183992 -0.489309,-0.74751 -0.242381,0.158659 -0.121325,-0.185351 q 0.09258,-0.08969 0.147241,-0.16621 0.05466,-0.07652 0.09725,-0.162581 l 0.219977,-0.143993 0.687965,1.050997 0.242382,-0.158659 0.158658,0.24238 -0.822873,0.53864 z"
id="path24674"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -47.003869,81.404714 0.294302,-0.162004 -0.430836,-0.782672 -0.253783,0.139699 -0.106826,-0.194069 q 0.09916,-0.08237 0.159495,-0.154489 0.06034,-0.07212 0.10937,-0.154686 l 0.230323,-0.126786 0.605754,1.100433 0.253782,-0.139699 0.139698,0.253781 -0.861579,0.474273 z"
id="path24676"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -45.851633,80.786314 0.305798,-0.139091 -0.369909,-0.813242 -0.263695,0.119943 -0.09172,-0.20165 q 0.105147,-0.07457 0.170811,-0.14188 0.06566,-0.06731 0.120844,-0.145896 l 0.23932,-0.108855 0.52009,1.143413 0.263694,-0.119942 0.119943,0.263694 -0.895231,0.407203 z"
id="path24678"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -44.102621,80.394743 q -0.116588,0.04268 -0.230173,0.02982 -0.114424,-0.01515 -0.21815,-0.08606 -0.101441,-0.07175 -0.192184,-0.199256 -0.08846,-0.128346 -0.156237,-0.313516 -0.06778,-0.185169 -0.08224,-0.338009 -0.01218,-0.153674 0.01981,-0.271668 0.03343,-0.121117 0.112714,-0.201983 0.07844,-0.08315 0.19503,-0.125829 0.116588,-0.04268 0.230173,-0.02982 0.112751,0.01058 0.214191,0.08232 0.102889,0.06862 0.19051,0.194684 0.0899,0.125225 0.157687,0.310393 0.06778,0.18517 0.08082,0.341125 0.0153,0.155123 -0.01813,0.276241 -0.03115,0.12028 -0.108755,0.205718 -0.07844,0.08315 -0.195029,0.125829 z m -0.09539,-0.260609 q 0.04344,-0.01588 0.07248,-0.04986 0.02821,-0.03625 0.03472,-0.103442 0.0065,-0.06719 -0.01492,-0.168227 -0.01914,-0.101871 -0.07353,-0.250465 -0.05439,-0.148593 -0.104698,-0.236464 -0.04886,-0.09099 -0.09554,-0.133531 -0.04751,-0.04482 -0.09162,-0.05201 -0.04411,-0.0072 -0.08754,0.0087 -0.04116,0.01504 -0.07019,0.04903 -0.02905,0.03397 -0.03639,0.09887 -0.0082,0.06262 0.01095,0.164493 0.0183,0.09959 0.0727,0.248177 0.05439,0.148594 0.105538,0.23875 0.05115,0.09016 0.0995,0.137265 0.04835,0.04711 0.0933,0.05658 0.04411,0.0072 0.08526,-0.0079 z"
id="path24680"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -43.423315,79.821211 0.323272,-0.0914 -0.243068,-0.859716 -0.278763,0.07882 -0.06027,-0.213173 q 0.11519,-0.05786 0.190248,-0.114507 0.07506,-0.05664 0.14146,-0.12601 l 0.252995,-0.07153 0.341754,1.208758 0.278763,-0.07882 0.07882,0.278764 -0.946391,0.267578 z"
id="path24682"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -41.635338,79.696896 q -0.121655,0.02478 -0.232046,-0.0049 -0.110875,-0.03207 -0.202844,-0.117684 -0.08958,-0.0861 -0.160258,-0.225733 -0.06829,-0.140122 -0.107647,-0.333338 -0.03935,-0.193218 -0.03083,-0.346501 0.01091,-0.15377 0.06017,-0.265661 0.05116,-0.114763 0.141626,-0.182877 0.08998,-0.0705 0.211639,-0.09528 0.121655,-0.02478 0.232046,0.0049 0.109904,0.0273 0.199487,0.113399 0.09148,0.08323 0.159286,0.220962 0.07019,0.137249 0.109544,0.330468 0.03935,0.193217 0.02893,0.349371 -0.008,0.155669 -0.0592,0.270432 -0.04877,0.114276 -0.138268,0.187162 -0.08998,0.0705 -0.21164,0.09528 z m -0.0554,-0.271931 q 0.04533,-0.0092 0.07912,-0.03848 0.03331,-0.03163 0.04979,-0.09709 0.01648,-0.06546 0.01039,-0.168569 -0.0037,-0.103586 -0.03529,-0.258639 -0.03156,-0.155056 -0.0682,-0.249452 -0.03472,-0.09727 -0.07452,-0.146306 -0.04028,-0.05142 -0.08283,-0.06511 -0.04254,-0.0137 -0.08786,-0.0045 -0.04294,0.0087 -0.07673,0.03798 -0.03379,0.02924 -0.05076,0.09232 -0.01745,0.0607 -0.01374,0.164282 0.0032,0.101203 0.0348,0.256254 0.03156,0.155056 0.06868,0.251838 0.03711,0.09679 0.07787,0.150591 0.04077,0.05381 0.08379,0.06989 0.04254,0.01369 0.08548,0.005 z"
id="path24684"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -40.8781,79.230957 0.333287,-0.04218 -0.112152,-0.886351 -0.2874,0.03636 -0.02781,-0.219776 q 0.12253,-0.04005 0.205197,-0.08485 0.08266,-0.04482 0.15867,-0.103503 l 0.260833,-0.03301 0.157684,1.246204 0.2874,-0.03636 0.03636,0.2874 -0.97571,0.123458 z"
id="path24686"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -39.091661,79.375257 q -0.123998,0.0062 -0.228672,-0.03973 -0.104795,-0.04837 -0.182851,-0.146835 -0.07563,-0.09858 -0.124512,-0.247255 -0.04646,-0.148793 -0.05632,-0.345732 -0.0099,-0.196937 0.02161,-0.347198 0.0339,-0.150382 0.09942,-0.253599 0.06782,-0.10577 0.167504,-0.159513 0.09956,-0.05617 0.223557,-0.06239 0.123998,-0.0062 0.228671,0.03973 0.104551,0.04351 0.180177,0.142095 0.07793,0.09603 0.124268,0.242392 0.04876,0.14624 0.05863,0.343179 0.0099,0.196937 -0.02391,0.349751 -0.03135,0.152691 -0.09917,0.258462 -0.06539,0.105647 -0.164829,0.164253 -0.09956,0.05617 -0.223556,0.06239 z m -0.01389,-0.277171 q 0.0462,-0.0023 0.08401,-0.02612 0.03768,-0.02627 0.06381,-0.08851 0.02613,-0.06225 0.0356,-0.165092 0.01191,-0.102969 0.004,-0.261005 -0.0079,-0.158037 -0.02993,-0.256869 -0.01974,-0.101377 -0.05168,-0.155843 -0.0321,-0.05689 -0.0721,-0.07682 -0.04,-0.01993 -0.08619,-0.01762 -0.04377,0.0022 -0.08157,0.02604 -0.0378,0.02383 -0.06406,0.08364 -0.02637,0.05738 -0.03828,0.160351 -0.01203,0.100538 -0.0041,0.258575 0.0079,0.158036 0.03005,0.259299 0.02216,0.101257 0.05436,0.160584 0.03222,0.05932 0.07234,0.08169 0.04,0.01993 0.08376,0.01774 z"
id="path24688"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -38.272706,79.028728 0.33583,0.0088 0.02339,-0.893112 -0.289593,-0.0076 0.0058,-0.221452 q 0.127181,-0.02102 0.215681,-0.0528 0.0885,-0.03178 0.172515,-0.07828 l 0.262824,0.0069 -0.03288,1.25571 0.289592,0.0076 -0.0076,0.289593 -0.983153,-0.02574 z"
id="path24690"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -36.528742,79.442398 q -0.123501,-0.01272 -0.219973,-0.07403 -0.09622,-0.06374 -0.158402,-0.172927 -0.05976,-0.108934 -0.08547,-0.263311 -0.02329,-0.154127 -0.0031,-0.350275 0.02019,-0.196148 0.07414,-0.339877 0.05637,-0.14348 0.136817,-0.235537 0.08311,-0.09423 0.189808,-0.132192 0.106942,-0.04038 0.230442,-0.02767 0.123502,0.01272 0.219973,0.07403 0.09672,0.0589 0.15648,0.167836 0.06243,0.106763 0.08597,0.258468 0.02596,0.151954 0.0058,0.348102 -0.02019,0.196148 -0.07681,0.34205 -0.0542,0.14615 -0.137315,0.240379 -0.08069,0.09448 -0.187886,0.137285 -0.106941,0.04038 -0.230442,0.02767 z m 0.02842,-0.276061 q 0.04601,0.0047 0.087,-0.01305 0.04124,-0.02023 0.07653,-0.07778 0.03529,-0.05755 0.06029,-0.15776 0.02742,-0.09996 0.04362,-0.257365 0.0162,-0.157403 0.0095,-0.258433 -0.0041,-0.103203 -0.02738,-0.16189 -0.02307,-0.06111 -0.05958,-0.08689 -0.0365,-0.02578 -0.08251,-0.03052 -0.04359,-0.0045 -0.08458,0.01328 -0.04099,0.01781 -0.07603,0.07293 -0.03479,0.0527 -0.06221,0.152668 -0.02717,0.09754 -0.04337,0.254943 -0.0162,0.157404 -0.0097,0.260854 0.0065,0.103452 0.02931,0.166982 0.02283,0.06353 0.05908,0.09173 0.0365,0.02579 0.08009,0.03027 z"
id="path24692"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -35.258558,79.622363 q -0.122171,-0.02209 -0.213687,-0.09059 -0.09108,-0.0709 -0.144753,-0.184504 -0.05127,-0.113175 -0.06511,-0.26907 -0.01147,-0.155454 0.02362,-0.349491 0.03509,-0.194038 0.09984,-0.333234 0.06715,-0.138763 0.15438,-0.224417 0.09006,-0.08761 0.199337,-0.117332 0.109715,-0.03209 0.23188,-0.01002 0.122172,0.02209 0.213688,0.09059 0.09195,0.06611 0.143224,0.17928 0.05411,0.111212 0.06599,0.264277 0.0143,0.15349 -0.02079,0.347528 -0.03509,0.194038 -0.102672,0.335197 -0.06519,0.141591 -0.155247,0.229207 -0.08767,0.08805 -0.197807,0.122557 -0.109714,0.03209 -0.231881,0.01002 z m 0.04939,-0.273091 q 0.04551,0.0082 0.08774,-0.0064 0.04266,-0.01704 0.08224,-0.07171 0.03958,-0.05469 0.07214,-0.152702 0.03496,-0.09758 0.06312,-0.25329 0.02816,-0.155709 0.02915,-0.256958 0.0038,-0.103212 -0.01496,-0.163507 -0.01832,-0.0627 -0.05278,-0.09118 -0.03443,-0.02849 -0.07995,-0.03672 -0.04312,-0.0078 -0.08534,0.0068 -0.04223,0.01465 -0.08137,0.06692 -0.03871,0.0499 -0.07367,0.147479 -0.03453,0.09519 -0.06269,0.250894 -0.02816,0.155709 -0.02958,0.259353 -0.0014,0.103645 0.01649,0.168732 0.01791,0.06509 0.05191,0.09597 0.03443,0.02849 0.07755,0.03629 z"
id="path24694"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264583px" />
<path
d="m -56.984661,107.17741 q 0.07998,0.13724 0.08934,0.28319 0.0067,0.14752 -0.05931,0.29412 -0.06755,0.1439 -0.20772,0.28688 -0.141749,0.14029 -0.359718,0.26731 -0.217968,0.12703 -0.40721,0.17964 -0.190808,0.0499 -0.346618,0.0362 -0.160068,-0.0149 -0.279754,-0.0965 -0.122376,-0.0801 -0.202356,-0.21732 -0.07998,-0.13724 -0.08934,-0.2832 -0.01205,-0.14438 0.05549,-0.28829 0.06328,-0.14502 0.20234,-0.28374 0.137488,-0.14141 0.355457,-0.26844 0.217969,-0.12703 0.411469,-0.17851 0.191932,-0.0542 0.352,-0.0393 0.1585,0.0122 0.283568,0.0907 0.122377,0.0801 0.202357,0.21733 z m -0.306772,0.17878 q -0.02979,-0.0511 -0.0791,-0.0801 -0.052,-0.0274 -0.138095,-0.0205 -0.0861,0.007 -0.208524,0.0566 -0.123998,0.047 -0.298911,0.14897 -0.174914,0.10193 -0.274266,0.18507 -0.103611,0.082 -0.146685,0.15037 -0.04576,0.0699 -0.04489,0.1271 8.73e-4,0.0572 0.03067,0.1083 0.02823,0.0484 0.07754,0.0774 0.04931,0.0289 0.132712,0.0236 0.08071,-0.004 0.20471,-0.0508 0.121308,-0.0455 0.296221,-0.1474 0.174913,-0.10194 0.276956,-0.18664 0.102043,-0.0847 0.150499,-0.1562 0.04845,-0.0715 0.05028,-0.13024 -8.73e-4,-0.0572 -0.0291,-0.1056 z"
id="path24173"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -57.860041,106.45069 -0.187597,-0.38671 -1.028434,0.4989 0.161769,0.33347 -0.255007,0.1237 q -0.09871,-0.13212 -0.186882,-0.21397 -0.08817,-0.0818 -0.190435,-0.14994 l -0.146816,-0.30265 1.445973,-0.70145 -0.161769,-0.33347 0.33347,-0.16177 0.549199,1.13212 z"
id="path24175"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -58.416288,104.22601 q 0.05825,0.14778 0.04536,0.29347 -0.01578,0.14682 -0.103223,0.28172 -0.08858,0.132 -0.248823,0.25206 -0.161382,0.11717 -0.396092,0.20968 -0.234712,0.0925 -0.429741,0.11581 -0.196173,0.0204 -0.348096,-0.0168 -0.155963,-0.039 -0.261882,-0.13782 -0.108817,-0.0977 -0.167061,-0.2455 -0.05824,-0.14778 -0.04536,-0.29347 0.01,-0.14454 0.09857,-0.27654 0.08454,-0.13375 0.243027,-0.24978 0.157343,-0.11892 0.392053,-0.21143 0.234711,-0.0925 0.433781,-0.11405 0.197928,-0.0245 0.353891,0.0145 0.154821,0.0361 0.266535,0.13265 0.108817,0.0977 0.167061,0.2455 z m -0.330333,0.13019 q -0.0217,-0.055 -0.06605,-0.0911 -0.04725,-0.0349 -0.133395,-0.0412 -0.08615,-0.006 -0.2147,0.0244 -0.129697,0.0277 -0.318045,0.10191 -0.188348,0.0742 -0.299157,0.14134 -0.11485,0.0654 -0.167791,0.12639 -0.05584,0.0622 -0.06365,0.11882 -0.0078,0.0566 0.0139,0.1117 0.02055,0.0522 0.06491,0.0883 0.04435,0.0361 0.127601,0.0434 0.08035,0.008 0.210046,-0.0192 0.126798,-0.0265 0.315146,-0.10078 0.188348,-0.0742 0.302056,-0.14248 0.113708,-0.0682 0.172445,-0.13157 0.05874,-0.0633 0.06944,-0.12111 0.0078,-0.0566 -0.01275,-0.1088 z"
id="path24177"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -58.959358,102.67724 q 0.0468,0.15179 0.02284,0.29607 -0.02694,0.14519 -0.124419,0.27302 -0.09839,0.12486 -0.26733,0.23235 -0.169851,0.10451 -0.410936,0.17884 -0.241085,0.0743 -0.437324,0.0827 -0.197157,0.005 -0.345798,-0.0433 -0.152536,-0.0507 -0.250603,-0.15741 -0.101044,-0.10573 -0.147842,-0.25753 -0.0468,-0.15179 -0.02284,-0.29607 0.02099,-0.14336 0.119383,-0.26821 0.0945,-0.12692 0.261377,-0.23051 0.165959,-0.10657 0.407043,-0.1809 0.241084,-0.0743 0.441218,-0.0806 0.199216,-0.009 0.351751,0.0415 0.151618,0.0478 0.255638,0.1526 0.101044,0.10573 0.147842,0.25753 z m -0.339304,0.1046 q -0.01744,-0.0565 -0.05891,-0.0959 -0.04445,-0.0384 -0.129866,-0.0512 -0.08541,-0.0128 -0.215933,0.008 -0.13143,0.0177 -0.324893,0.0773 -0.193463,0.0597 -0.30907,0.1181 -0.119501,0.0564 -0.176945,0.11322 -0.06043,0.0578 -0.07252,0.11362 -0.01211,0.0559 0.0053,0.11243 0.01652,0.0536 0.05799,0.0929 0.04147,0.0394 0.123913,0.0531 0.07947,0.0146 0.210898,-0.003 0.128454,-0.0168 0.321917,-0.0764 0.193462,-0.0596 0.312046,-0.11902 0.118583,-0.0594 0.181981,-0.11803 0.06339,-0.0587 0.07848,-0.11545 0.0121,-0.0559 -0.0044,-0.10946 z"
id="path24179"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -59.647133,101.77095 -0.09493,-0.4192 -1.114829,0.25245 0.08186,0.36149 -0.276429,0.0626 q -0.06614,-0.15108 -0.133439,-0.2508 -0.06729,-0.0997 -0.151434,-0.18925 l -0.07429,-0.32807 1.567444,-0.35496 -0.08187,-0.36148 0.361484,-0.0819 0.27791,1.22722 z"
id="path24181"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -59.999268,100.13551 -0.06278,-0.425207 -1.130798,0.166957 0.05413,0.36666 -0.280389,0.0414 q -0.05447,-0.15567 -0.113982,-0.26022 -0.05952,-0.104558 -0.136605,-0.200219 l -0.04913,-0.332769 1.589895,-0.234742 -0.05413,-0.366662 0.366661,-0.05413 0.183791,1.244802 z"
id="path24183"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -60.226075,98.478211 -0.0305,-0.42873 -1.140175,0.08111 0.0263,0.369703 -0.282714,0.02011 q -0.04256,-0.159339 -0.09401,-0.268088 -0.05145,-0.108748 -0.121101,-0.209957 l -0.02387,-0.335528 1.603079,-0.114049 -0.0263,-0.369703 0.369703,-0.0263 0.08929,1.255125 z"
id="path24185"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -59.917022,96.205666 q -5.93e-4,0.158844 -0.06649,0.289411 -0.069,0.130557 -0.200169,0.223507 -0.131149,0.08983 -0.324451,0.142061 -0.193289,0.04911 -0.445569,0.04818 -0.252281,-9.42e-4 -0.442084,-0.05148 -0.189792,-0.05366 -0.317152,-0.144456 -0.130464,-0.09393 -0.192267,-0.224969 -0.06492,-0.131057 -0.06433,-0.2899 5.93e-4,-0.158843 0.06649,-0.289412 0.06278,-0.130579 0.193929,-0.220413 0.128047,-0.09296 0.318222,-0.142085 0.190186,-0.05224 0.442467,-0.0513 0.25228,9.4e-4 0.445187,0.05461 0.192917,0.05055 0.32338,0.144478 0.130476,0.09081 0.198508,0.221879 0.06492,0.131056 0.06432,0.289899 z m -0.355061,-0.0013 q 2.2e-4,-0.05918 -0.02762,-0.109115 -0.03096,-0.04995 -0.108684,-0.08761 -0.07772,-0.03766 -0.208468,-0.05684 -0.130731,-0.02229 -0.333178,-0.02305 -0.202447,-7.55e-4 -0.330226,0.02057 -0.130882,0.0182 -0.202656,0.05531 -0.07489,0.0371 -0.103107,0.08683 -0.02822,0.04972 -0.02844,0.108905 -2.09e-4,0.05607 0.02763,0.106001 0.02784,0.04994 0.102456,0.08759 0.0715,0.03764 0.202227,0.05993 0.127615,0.02228 0.330063,0.02304 0.202447,7.56e-4 0.333341,-0.02056 0.130893,-0.02131 0.208897,-0.0584 0.078,-0.03708 0.109335,-0.08681 0.02822,-0.04972 0.02842,-0.10579 z"
id="path24187"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -59.849693,94.565757 q -0.01246,0.158354 -0.08794,0.283631 -0.07858,0.125032 -0.216319,0.207915 -0.137498,0.07977 -0.334163,0.117409 -0.196421,0.03453 -0.447924,0.01472 -0.251505,-0.0198 -0.436999,-0.08439 -0.185248,-0.06769 -0.305464,-0.167762 -0.123076,-0.103416 -0.17491,-0.238714 -0.05494,-0.135543 -0.04248,-0.293897 0.01247,-0.158355 0.08794,-0.283631 0.07237,-0.125521 0.209864,-0.205299 0.134638,-0.08313 0.327953,-0.117897 0.19356,-0.03787 0.445064,-0.01808 0.251504,0.0198 0.439858,0.08774 0.188599,0.06483 0.311675,0.168251 0.123321,0.100311 0.181364,0.236098 0.05494,0.135543 0.04248,0.293897 z m -0.353969,-0.02787 q 0.0046,-0.05899 -0.01939,-0.110875 -0.02714,-0.05212 -0.101831,-0.09549 -0.0747,-0.04337 -0.203634,-0.07227 -0.128698,-0.032 -0.330523,-0.04789 -0.201824,-0.01589 -0.330839,-0.0041 -0.131877,0.0084 -0.206225,0.04 -0.07746,0.03139 -0.109309,0.07888 -0.03185,0.04748 -0.0365,0.106476 -0.0044,0.05589 0.01964,0.107769 0.02403,0.05187 0.09562,0.09501 0.06848,0.04288 0.197181,0.07488 0.125594,0.03176 0.327417,0.04764 0.201824,0.01589 0.333945,0.0044 0.132121,-0.01147 0.212679,-0.04261 0.08056,-0.03115 0.115519,-0.07838 0.03185,-0.04748 0.03625,-0.10337 z"
id="path24189"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -59.659265,92.935531 q -0.0244,0.15696 -0.109117,0.276175 -0.0878,0.118738 -0.231411,0.190976 -0.143133,0.06916 -0.342079,0.09183 -0.198467,0.01959 -0.447757,-0.01916 -0.249289,-0.03875 -0.429372,-0.117168 -0.179604,-0.0815 -0.291915,-0.190364 -0.11491,-0.11242 -0.156372,-0.251248 -0.04454,-0.139307 -0.02015,-0.296266 0.0244,-0.15696 0.109117,-0.276175 0.08165,-0.119695 0.224777,-0.188855 0.140533,-0.07271 0.335924,-0.09278 0.195868,-0.02314 0.445157,0.01561 0.249289,0.03875 0.431971,0.120724 0.18316,0.0789 0.29807,0.191321 0.115389,0.109343 0.163006,0.249127 0.04454,0.139306 0.02015,0.296267 z m -0.350851,-0.05454 q 0.0091,-0.05847 -0.01096,-0.112023 -0.02313,-0.05402 -0.09432,-0.102916 -0.0712,-0.0489 -0.197591,-0.08745 -0.125913,-0.04164 -0.32596,-0.07272 -0.200046,-0.0311 -0.329578,-0.02916 -0.132131,-0.0016 -0.208657,0.02431 -0.07961,0.02545 -0.114957,0.07039 -0.03536,0.04494 -0.04444,0.103412 -0.0086,0.0554 0.01143,0.108945 0.02005,0.05355 0.08817,0.101959 0.06505,0.04793 0.190958,0.08957 0.122835,0.04115 0.322881,0.07225 0.200047,0.0311 0.332657,0.02965 0.132609,-0.0015 0.21529,-0.02643 0.08268,-0.02497 0.121112,-0.06943 0.03535,-0.04494 0.04397,-0.100335 z"
id="path24191"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -59.8809,91.81956 0.09813,-0.418462 -1.112867,-0.260972 -0.08462,0.360847 -0.275942,-0.0647 q 0.0066,-0.164793 -0.0102,-0.283912 -0.01685,-0.11912 -0.05332,-0.23644 l 0.0768,-0.327493 1.564685,0.366926 0.08462,-0.360848 0.360847,0.08462 -0.287282,1.225063 z"
id="path24193"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -58.910282,89.741954 q -0.04796,0.151431 -0.14981,0.256392 -0.104818,0.104019 -0.257738,0.153601 -0.151978,0.04661 -0.352058,0.03879 -0.199139,-0.0108 -0.439648,-0.08696 -0.240509,-0.07617 -0.406586,-0.181041 -0.165138,-0.107841 -0.259606,-0.232505 -0.0965,-0.128572 -0.116386,-0.272088 -0.02286,-0.144456 0.0251,-0.295887 0.04796,-0.151432 0.149809,-0.256392 0.09888,-0.105901 0.250859,-0.152513 0.149951,-0.05052 0.34612,-0.04067 0.19711,0.0069 0.437619,0.08306 0.240509,0.07618 0.408615,0.184951 0.169048,0.105811 0.265545,0.234384 0.09744,0.125603 0.123264,0.271 0.02286,0.144456 -0.0251,0.295888 z m -0.338494,-0.107204 q 0.01787,-0.05641 0.0062,-0.112386 -0.01465,-0.05691 -0.07759,-0.116052 -0.06295,-0.05914 -0.182013,-0.116451 -0.118125,-0.06028 -0.311126,-0.121405 -0.193001,-0.06113 -0.321323,-0.0789 -0.13035,-0.02168 -0.209928,-0.0077 -0.08255,0.01306 -0.124314,0.05211 -0.04177,0.03904 -0.05964,0.09547 -0.01692,0.05344 -0.0052,0.109417 0.01168,0.05597 0.07166,0.114171 0.05701,0.05726 0.175133,0.11754 0.115156,0.05934 0.308157,0.120465 0.193001,0.06113 0.324292,0.07983 0.13129,0.01871 0.216806,0.0066 0.08551,-0.01212 0.130255,-0.05023 0.04176,-0.03904 0.0587,-0.09249 z"
id="path24195"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -58.959628,88.605248 0.160654,-0.398662 -1.060207,-0.427247 -0.138535,0.343773 -0.262885,-0.105938 q 0.03165,-0.161863 0.03312,-0.282159 0.0015,-0.120297 -0.01673,-0.241801 l 0.125729,-0.311995 1.490645,0.600707 0.138535,-0.343773 0.343772,0.138535 -0.470321,1.167094 z"
id="path24197"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -57.684281,86.699484 q -0.07041,0.142383 -0.187036,0.230644 -0.11941,0.08688 -0.278088,0.112646 -0.157299,0.02297 -0.353865,-0.01517 -0.195184,-0.04094 -0.421322,-0.152774 -0.226138,-0.111839 -0.374348,-0.240733 -0.14683,-0.131684 -0.221254,-0.269258 -0.07584,-0.141744 -0.07368,-0.286616 -6.38e-4,-0.146252 0.06978,-0.288636 0.07041,-0.142383 0.187036,-0.230644 0.113827,-0.08965 0.271125,-0.112615 0.155886,-0.02714 0.34828,0.01241 0.193774,0.03677 0.419912,0.148602 0.226138,0.111839 0.375759,0.244905 0.151001,0.130273 0.226836,0.272019 0.07722,0.138953 0.08064,0.286586 6.38e-4,0.146252 -0.06978,0.288636 z m -0.318268,-0.157403 q 0.02623,-0.05305 0.0232,-0.11014 -0.0058,-0.05847 -0.05905,-0.126498 -0.05323,-0.06802 -0.162199,-0.142761 -0.107592,-0.07753 -0.289061,-0.16728 -0.181469,-0.08974 -0.305599,-0.126814 -0.125541,-0.04124 -0.206322,-0.0395 -0.08357,3.65e-4 -0.13079,0.0326 -0.04722,0.03224 -0.07345,0.08529 -0.02485,0.05026 -0.02181,0.10735 0.0031,0.05709 0.05347,0.123735 0.04764,0.06526 0.155236,0.142791 0.1048,0.07615 0.286269,0.1659 0.181468,0.08974 0.30839,0.128194 0.126922,0.03845 0.213286,0.03947 0.08636,9.86e-4 0.136374,-0.02984 0.04722,-0.03224 0.07207,-0.0825 z"
id="path24199"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -57.56043,85.568621 0.219233,-0.369699 -0.983185,-0.583032 -0.189048,0.318799 -0.243788,-0.144567 q 0.05582,-0.155194 0.0755,-0.273878 0.01968,-0.118684 0.02012,-0.241542 l 0.171574,-0.289329 1.382352,0.81974 0.189049,-0.318799 0.318798,0.189049 -0.641812,1.082307 z"
id="path24201"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -56.011241,83.878005 q -0.09113,0.130108 -0.219742,0.199733 -0.131169,0.06784 -0.291918,0.06933 -0.158963,-0.0011 -0.347507,-0.06847 -0.186757,-0.06996 -0.393398,-0.214689 -0.206641,-0.144727 -0.333671,-0.294537 -0.125243,-0.152361 -0.178023,-0.299602 -0.05354,-0.151577 -0.02953,-0.294459 0.02147,-0.144668 0.112595,-0.274776 0.09113,-0.130107 0.219742,-0.199731 0.126067,-0.07141 0.285029,-0.07036 0.158198,-0.0033 0.342405,0.0649 0.185993,0.06562 0.392634,0.21035 0.20664,0.144727 0.334434,0.298876 0.129582,0.151596 0.183126,0.303173 0.05534,0.149027 0.03641,0.295482 -0.02147,0.144669 -0.112595,0.274776 z m -0.290827,-0.20369 q 0.03394,-0.04847 0.03958,-0.10537 0.0031,-0.05869 -0.03926,-0.133968 -0.04234,-0.07528 -0.138763,-0.165633 -0.09464,-0.0929 -0.260462,-0.20904 -0.165823,-0.116139 -0.282926,-0.171539 -0.117868,-0.05973 -0.197985,-0.07022 -0.08266,-0.01227 -0.134215,0.01247 -0.05155,0.02473 -0.08549,0.07321 -0.03216,0.04592 -0.03779,0.102819 -0.0056,0.05689 0.03416,0.130394 0.03724,0.07171 0.131874,0.164611 0.09209,0.09112 0.257912,0.207253 0.165823,0.11614 0.285477,0.173326 0.119654,0.05719 0.204873,0.07124 0.08522,0.01405 0.139319,-0.0089 0.05155,-0.02473 0.08371,-0.07066 z"
id="path24203"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -55.718131,82.778904 0.272428,-0.33245 -0.884126,-0.724501 -0.234919,0.286678 -0.219225,-0.179645 q 0.07856,-0.145012 0.115905,-0.259376 0.03734,-0.114364 0.05628,-0.235754 l 0.213204,-0.260179 1.243076,1.018644 0.23492,-0.286678 0.286678,0.23492 -0.797543,0.97326 z"
id="path24205"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -53.932145,81.340744 q -0.109646,0.114932 -0.247268,0.164434 -0.139875,0.04735 -0.299022,0.02466 -0.156997,-0.02494 -0.333267,-0.119928 -0.17412,-0.09724 -0.356658,-0.271381 -0.182539,-0.174144 -0.285608,-0.341345 -0.100919,-0.169457 -0.130968,-0.322956 -0.03015,-0.157904 0.01507,-0.295552 0.04297,-0.139798 0.152618,-0.25473 0.109646,-0.114932 0.247268,-0.164433 0.135367,-0.05165 0.292364,-0.02671 0.156894,0.02054 0.328761,0.115627 0.174015,0.09283 0.356555,0.266978 0.182539,0.174143 0.28571,0.345749 0.105323,0.169352 0.135475,0.327255 0.0323,0.155651 -0.0084,0.297599 -0.04297,0.139798 -0.152617,0.254729 z m -0.256907,-0.24509 q 0.04085,-0.04282 0.05496,-0.09823 0.01186,-0.05755 -0.01868,-0.138347 -0.03054,-0.08079 -0.112291,-0.184609 -0.0796,-0.106072 -0.226083,-0.245817 -0.146481,-0.139743 -0.253926,-0.212116 -0.107549,-0.07678 -0.18518,-0.09918 -0.07988,-0.02456 -0.134566,-0.0079 -0.05468,0.01671 -0.09553,0.05953 -0.0387,0.04056 -0.05281,0.09597 -0.01411,0.0554 0.01417,0.134047 0.02604,0.07649 0.105634,0.182563 0.07735,0.103921 0.223828,0.243666 0.146482,0.139745 0.256181,0.214267 0.109699,0.07452 0.191837,0.101226 0.08214,0.02671 0.139073,0.01215 0.05468,-0.01671 0.09338,-0.05727 z"
id="path24207"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -53.477252,80.298167 0.319254,-0.287778 -0.765323,-0.849034 -0.2753,0.248157 -0.189767,-0.210523 q 0.09945,-0.131573 0.153535,-0.239034 0.05409,-0.107461 0.09104,-0.224631 l 0.249853,-0.225218 1.076041,1.193736 0.275299,-0.248156 0.248157,0.275299 -0.934631,0.842482 z"
id="path24209"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -52.223176,79.191269 0.34003,-0.262907 -0.69918,-0.904282 -0.293214,0.226709 -0.173367,-0.224222 q 0.109076,-0.123706 0.171107,-0.226787 0.06203,-0.10308 0.107706,-0.217133 l 0.26611,-0.205753 0.983043,1.271414 0.293214,-0.226709 0.22671,0.293214 -0.995449,0.76967 z"
id="path24211"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -50.889212,78.181994 0.358911,-0.236481 -0.628901,-0.954495 -0.309496,0.203922 -0.155941,-0.236673 q 0.118106,-0.115117 0.187745,-0.213219 0.06964,-0.0981 0.123792,-0.208381 l 0.280887,-0.185072 0.884232,1.342015 0.309496,-0.203922 0.203923,0.309496 -1.050726,0.692306 z"
id="path24213"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -48.756416,77.339766 q -0.13888,0.0771 -0.284997,0.0834 -0.147629,0.0036 -0.292815,-0.06543 -0.142463,-0.07053 -0.282483,-0.213666 -0.137296,-0.144647 -0.259745,-0.36522 -0.12245,-0.220573 -0.171095,-0.410871 -0.04592,-0.19181 -0.02894,-0.347299 0.01821,-0.159722 0.102338,-0.277677 0.08262,-0.120677 0.221504,-0.197775 0.138881,-0.0771 0.284997,-0.0834 0.144606,-0.0091 0.287069,0.0615 0.143674,0.06629 0.279459,0.208219 0.138509,0.140411 0.260958,0.360984 0.122448,0.220573 0.169882,0.415107 0.05016,0.193021 0.03195,0.352744 -0.01548,0.158211 -0.09659,0.281612 -0.08262,0.120678 -0.221504,0.197776 z m -0.172336,-0.310437 q 0.05174,-0.02872 0.08171,-0.07742 0.02845,-0.05142 0.02333,-0.137637 -0.0051,-0.08621 -0.05227,-0.209661 -0.04443,-0.124953 -0.142692,-0.301957 -0.09826,-0.177002 -0.179304,-0.278068 -0.07983,-0.105302 -0.147278,-0.149793 -0.06896,-0.04721 -0.126134,-0.04754 -0.05717,-3.2e-4 -0.108916,0.0284 -0.04901,0.02721 -0.07897,0.07591 -0.02996,0.0487 -0.02636,0.132191 0.0021,0.08077 0.04652,0.205725 0.04292,0.12223 0.141181,0.299234 0.09826,0.177003 0.180815,0.280793 0.08255,0.103789 0.153026,0.153726 0.07047,0.04994 0.129157,0.05298 0.05718,3.2e-4 0.106192,-0.02689 z"
id="path24215"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -48.011571,76.479761 0.390558,-0.179458 -0.47725,-1.038657 -0.336785,0.154749 -0.118337,-0.257542 q 0.134162,-0.09593 0.217841,-0.18236 0.08368,-0.08644 0.153895,-0.187253 l 0.305655,-0.140445 0.671011,1.460349 0.336785,-0.154749 0.154749,0.336786 -1.143374,0.525365 z"
id="path24217"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -45.775734,75.970283 q -0.148971,0.05513 -0.294353,0.03919 -0.146463,-0.01887 -0.279492,-0.109115 -0.130109,-0.09133 -0.246786,-0.254061 -0.113754,-0.163807 -0.201311,-0.400408 -0.08755,-0.236601 -0.10676,-0.432077 -0.01628,-0.196558 0.02411,-0.347666 0.04223,-0.155111 0.143293,-0.258931 0.09998,-0.106741 0.248953,-0.16187 0.148971,-0.05513 0.294353,-0.03919 0.144301,0.01302 0.274411,0.104354 0.131949,0.08733 0.244623,0.248219 0.115594,0.159805 0.203152,0.396406 0.08756,0.236601 0.104919,0.436079 0.02029,0.198397 -0.02194,0.353508 -0.03931,0.15403 -0.138211,0.263692 -0.09998,0.106741 -0.248953,0.161869 z m -0.123228,-0.332994 q 0.05549,-0.02054 0.09251,-0.06412 0.03593,-0.04651 0.04395,-0.132502 0.008,-0.086 -0.01984,-0.215164 -0.02495,-0.130249 -0.09522,-0.320114 -0.07027,-0.189865 -0.135028,-0.302059 -0.06293,-0.116197 -0.12284,-0.170408 -0.061,-0.05713 -0.117459,-0.06612 -0.05647,-0.009 -0.111964,0.01155 -0.05257,0.01946 -0.08959,0.06304 -0.037,0.04358 -0.04611,0.126659 -0.01019,0.08016 0.01476,0.210404 0.02388,0.127327 0.09413,0.317193 0.07027,0.189865 0.136109,0.30498 0.06585,0.115116 0.127923,0.17517 0.06207,0.06005 0.119622,0.07196 0.05646,0.009 0.109042,-0.01046 z"
id="path24219"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -44.908808,75.233344 0.413307,-0.117973 -0.313743,-1.099157 -0.356403,0.101732 -0.07779,-0.272543 q 0.14719,-0.07441 0.24304,-0.147109 0.09585,-0.0727 0.180583,-0.161671 l 0.323457,-0.09233 0.441121,1.545407 0.356402,-0.101732 0.101731,0.356402 -1.20997,0.345374 z"
id="path24221"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -42.621453,75.069922 q -0.155624,0.03182 -0.296889,-0.006 -0.141889,-0.04092 -0.259643,-0.150359 -0.114702,-0.110064 -0.205267,-0.288644 -0.08752,-0.179204 -0.138063,-0.42637 -0.05055,-0.247167 -0.03979,-0.443289 0.01381,-0.196747 0.07672,-0.339953 0.06534,-0.146883 0.181011,-0.234121 0.115056,-0.09029 0.270679,-0.122118 0.155623,-0.03182 0.296889,0.006 0.140641,0.03482 0.255343,0.144882 0.117129,0.106387 0.204019,0.282541 0.08994,0.175528 0.14049,0.422694 0.05055,0.247167 0.03737,0.446965 -0.01013,0.199173 -0.07546,0.346055 -0.06228,0.146258 -0.176713,0.2396 -0.115055,0.09029 -0.270678,0.122117 z m -0.07114,-0.347864 q 0.05798,-0.01185 0.101185,-0.04931 0.04258,-0.0405 0.0636,-0.124273 0.02102,-0.08378 0.01312,-0.21568 -0.0048,-0.132528 -0.04541,-0.330872 -0.04056,-0.198343 -0.08751,-0.319084 -0.04452,-0.124416 -0.09549,-0.18711 -0.0516,-0.06575 -0.106035,-0.08322 -0.05444,-0.01748 -0.112416,-0.0056 -0.05492,0.01123 -0.09814,0.04868 -0.04321,0.03745 -0.06484,0.118171 -0.02227,0.07767 -0.01742,0.2102 0.0042,0.129478 0.04479,0.327821 0.04056,0.198343 0.08814,0.322135 0.04758,0.123792 0.09979,0.19259 0.05222,0.0688 0.107282,0.08933 0.05444,0.01748 0.109365,0.0062 z"
id="path24223"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -41.002095,74.802504 q -0.157591,0.01992 -0.295573,-0.02856 -0.138373,-0.05158 -0.247479,-0.169639 -0.106015,-0.118453 -0.182761,-0.303394 -0.07366,-0.185331 -0.105294,-0.435621 -0.03164,-0.25029 -0.006,-0.445031 0.02871,-0.19513 0.1023,-0.333147 0.07629,-0.141499 0.198264,-0.219703 0.121578,-0.08129 0.279169,-0.101215 0.15759,-0.01992 0.295573,0.02856 0.137593,0.04539 0.243607,0.163849 0.108714,0.114972 0.18198,0.297214 0.07635,0.181851 0.107995,0.432141 0.03164,0.25029 0.0034,0.448511 -0.02523,0.197829 -0.101519,0.339328 -0.07321,0.141107 -0.194393,0.225492 -0.121579,0.08129 -0.279169,0.101215 z m -0.04453,-0.352261 q 0.05871,-0.0074 0.104635,-0.04148 0.04553,-0.03715 0.07285,-0.119087 0.02732,-0.08193 0.02945,-0.214062 0.0052,-0.132514 -0.02016,-0.333365 -0.02538,-0.20085 -0.06303,-0.324807 -0.03494,-0.127436 -0.08101,-0.193819 -0.04645,-0.06947 -0.09941,-0.09104 -0.05296,-0.02156 -0.111665,-0.01414 -0.05562,0.007 -0.101545,0.04109 -0.04593,0.03406 -0.07363,0.112906 -0.0281,0.07576 -0.03332,0.208272 -0.0056,0.129425 0.01977,0.330275 0.02538,0.200851 0.06342,0.327897 0.03804,0.127046 0.08488,0.199609 0.04684,0.07256 0.100191,0.09721 0.05296,0.02156 0.108575,0.01453 z"
id="path24225"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -39.367077,74.658341 q -0.158643,0.008 -0.292584,-0.05074 -0.134098,-0.06185 -0.234006,-0.187788 -0.0968,-0.126098 -0.159401,-0.316291 -0.0595,-0.19035 -0.0722,-0.442313 -0.0127,-0.251962 0.0275,-0.44422 0.04331,-0.192416 0.12709,-0.324501 0.08674,-0.135354 0.214242,-0.204154 0.127352,-0.07191 0.285995,-0.07991 0.158643,-0.008 0.292584,0.05074 0.133784,0.05562 0.23058,0.181724 0.09975,0.12283 0.15909,0.31007 0.06245,0.187082 0.07516,0.439044 0.0127,0.251962 -0.03045,0.447489 -0.04005,0.19537 -0.126776,0.330722 -0.08362,0.135196 -0.210817,0.210218 -0.127353,0.07191 -0.285996,0.07991 z m -0.01788,-0.354614 q 0.0591,-0.003 0.107461,-0.03348 0.04821,-0.03362 0.08161,-0.113264 0.0334,-0.07965 0.04548,-0.211237 0.01519,-0.131744 0.005,-0.333937 -0.0102,-0.202191 -0.0384,-0.32863 -0.02525,-0.129706 -0.06618,-0.199368 -0.04109,-0.07277 -0.09227,-0.09826 -0.05118,-0.02548 -0.110285,-0.0225 -0.056,0.0029 -0.10435,0.03332 -0.04836,0.0305 -0.08192,0.107044 -0.03372,0.07342 -0.04891,0.205172 -0.01535,0.128635 -0.0051,0.330826 0.0102,0.202192 0.03856,0.331741 0.02836,0.129549 0.06961,0.205433 0.04125,0.07589 0.09258,0.10448 0.05118,0.02548 0.107174,0.02266 z"
id="path24227"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -38.319919,74.214433 0.429689,0.01041 0.02769,-1.142721 -0.370528,-0.009 0.0069,-0.283345 q 0.162666,-0.02721 0.275815,-0.06809 0.113148,-0.04088 0.220523,-0.100585 l 0.336277,0.0082 -0.03894,1.606659 0.370528,0.009 -0.009,0.370529 -1.257928,-0.03048 z"
id="path24229"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -36.087476,74.738076 q -0.158062,-0.01575 -0.281747,-0.0938 -0.123375,-0.08115 -0.203386,-0.220583 -0.07691,-0.139123 -0.110455,-0.336525 -0.03044,-0.197094 -0.0054,-0.448134 0.02501,-0.25104 0.09343,-0.435154 0.07152,-0.183805 0.174058,-0.301921 0.105946,-0.120906 0.242289,-0.169924 0.136653,-0.05212 0.294715,-0.03637 0.158062,0.01575 0.281746,0.0938 0.123995,0.07495 0.200905,0.214075 0.08032,0.136332 0.111073,0.330327 0.03386,0.194303 0.0089,0.445342 -0.02501,0.25104 -0.09683,0.437945 -0.06873,0.187214 -0.174676,0.30812 -0.102846,0.121215 -0.239807,0.176431 -0.136652,0.05211 -0.294715,0.03637 z m 0.0352,-0.353315 q 0.05889,0.0058 0.111253,-0.01709 0.05267,-0.02605 0.09759,-0.09983 0.04491,-0.07378 0.07647,-0.202093 0.03466,-0.128007 0.05473,-0.329458 0.02007,-0.201452 0.01104,-0.330682 -0.0056,-0.132022 -0.03572,-0.20701 -0.02978,-0.07809 -0.07659,-0.11092 -0.0468,-0.03283 -0.105695,-0.0387 -0.05579,-0.0055 -0.108153,0.0174 -0.05237,0.02295 -0.09697,0.09363 -0.04429,0.06758 -0.07896,0.195586 -0.03435,0.124907 -0.05442,0.326359 -0.02007,0.201452 -0.01134,0.333781 0.0087,0.132331 0.0382,0.213517 0.02947,0.08118 0.07598,0.11712 0.0468,0.03283 0.102595,0.03839 z"
id="path24231"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
<path
d="m -34.985501,74.455384 0.423241,0.07488 0.199131,-1.125578 -0.36497,-0.06457 0.04938,-0.279093 q 0.164908,-0.0025 0.282915,-0.02586 0.118007,-0.0234 0.233136,-0.06629 l 0.331233,0.0586 -0.279976,1.582557 0.364969,0.06457 -0.06457,0.364969 -1.239056,-0.219205 z"
id="path24233"
style="font-weight:bold;font-size:3.15817px;line-height:2.46731px;font-family:'Source Sans Pro';-inkscape-font-specification:'Source Sans Pro Bold';letter-spacing:0px;word-spacing:0px;fill:#5abdf6;stroke-width:0.264582px" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 93 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 217 KiB

View File

@@ -0,0 +1,10 @@
:root {
--bs-primary: #008aff;
--bs-primary-rgb: 0,138,255;
--bs-secondary: #48092f;
--bs-secondary-rgb: 72,9,47;
}
.ak-navbar {
background-color: #e3f2fd;
}

View File

@@ -0,0 +1,10 @@
.ak-docs-markdown p > img {
margin: 0 auto;
display: block;
max-width: 100%;
}
.ak-docs-toc ul {
padding-left: 0;
list-style: none;
}

46
web/data/docs/00-intro.md Normal file
View File

@@ -0,0 +1,46 @@
![](../assets/images/akvorado.svg)
# Introduction
*Akvorado*[^name] is a flow collector, hydrater and exporter. It
receives flows, adds some data like interface names and countries, and
exports them to Kafka.
[^name]: [Akvorado][] means "water wheel" in Esperanto.
[Akvorado]: https://eo.wikipedia.org/wiki/Akvorado
## Big picture
The general design of *Akvorado* is the following:
- The exporters send Netflow and IPFIX flows to Akvorado. They don't
need to be declared as Akvorado accepts flows from anyone.
- The received flows are decoded and hydrated with additional
information:
- source and destination countries (GeoIP database)
- source and destination AS numbers (GeoIP database)
- source and destination interface names, descriptions and speeds (SNMP)
- The SNMP poller queries the exporters for host names, interface
names, interface descriptions and interface speeds. This information
is cached and updated from time to time.
- Once a flow is hydrated, it is transformed into a binary
representation using *protocol buffers* and sent to Kafka.
The remaining steps are outside of *Akvorado* control:
- ClickHouse subscribes to the Kafka topic to receive and store the
flows.
- Grafana queries ClickHouse to build various dashboards.
## Flow schema
Flows sent to Kafka are encoded with a versioned schema, described in
the `flow-*.proto` files. Any information that could change with time
is embedded in the flow. This includes for example interface names and
speeds, as well. This ensures that older data are not processed using
incorrect mappings.
Each time the schema changes, we issue a new `flow-*.proto` file,
update the schema version and a new Kafka topic will be used. This
ensures we do not mix different schemas in a single topic.

View File

@@ -1,21 +1,8 @@
# Configuration # Configuration
*Akvorado* can be configured through a YAML file. Each aspect is *Akvorado* can be configured through a YAML file. You can get the
configured through a different section: default configuration with `./akvorado --dump --check`. Durations can
be written in seconds or using strings like `10h20m`.
- `reporting`: [Log and metric reporting](#reporting)
- `http`: [Builtin HTTP server](#http)
- `web`: [Web interface](#web)
- `flow`: [Flow ingestion](#flow)
- `snmp`: [SNMP poller](#snmp)
- `geoip`: [GeoIP database](#geoip)
- `kafka`: [Kafka broker](#kafka)
- `clickhouse`: [ClickHouse helper](#clickhouse)
- `core`: [Core](#core)
You can get the default configuration with `./akvorado --dump
--check`. Durations can be written in seconds or using strings like
`10h20m`.
It is also possible to override configuration settings using It is also possible to override configuration settings using
environment variables. You need to remove any `-` from key names and environment variables. You need to remove any `-` from key names and
@@ -40,43 +27,14 @@ AKVORADO_KAFKA_TOPICCONFIGURATION_NUMPARTITIONS=1
AKVORADO_KAFKA_BROKERS=192.0.2.1:9092,192.0.2.2:9092 AKVORADO_KAFKA_BROKERS=192.0.2.1:9092,192.0.2.2:9092
``` ```
## Reporting
Reporting encompasses logging and metrics. Currently, as *Akvorado* is
expected to be run inside Docker, logging is done on the standard
output and is not configurable. As for metrics, they are reported by
the HTTP component on the `/api/v0/metrics` endpoint and there is
nothing to configure either.
## HTTP
The builtin HTTP server serves various pages. Its configuration
supports only the `listen` key to specify the address and port to
listen. For example:
```yaml
http:
listen: 0.0.0.0:8000
```
## Web
The web interface presents the landing page of *Akvorado*. It also
embeds the documentation. It accepts only the following key:
- `grafanaurl` to specify the URL to Grafana and exposes it as
[`/grafana`](/grafana).
## Flow ## Flow
The flow component handles flow ingestion. It supports the following The flow component handles incoming flows. It only accepts the
configuration keys: `inputs` key to define the list of inputs to receive incoming flows.
- `inputs` to specify the list of inputs Each input has a `type` and a `decoder`. For `decoder`, only `netflow`
is currently supported. As for the `type`, both `udp` and `file` are
Each input should define a `type` and `decoder`. For `decoder`, only supported.
`netflow` is currently supported. As for the `type`, both `udp` and
`file` are supported.
For the UDP input, the supported keys are `listen` to set the For the UDP input, the supported keys are `listen` to set the
listening endpoint, `workers` to set the number of workers to listen listening endpoint, `workers` to set the number of workers to listen
@@ -109,46 +67,8 @@ flow:
workers: 2 workers: 2
``` ```
## SNMP Without configuration, *Akvorado* will listen for incoming
Netflow/IPFIX flows on port 2055.
Flows only include interface indexes. To associate them with an
interface name and description, SNMP is used to poll the exporter
sending each flows. A cache is maintained to avoid polling
continuously the exporters. The following keys are accepted:
- `cache-duration` tells how much time to keep data in the cache
- `cache-refresh` tells how much time to wait before updating an entry
by polling it
- `cache-check-interval` tells how often to check if cached data is
about to expire or need an update
- `cache-persist-file` tells where to store cached data on shutdown and
read them back on startup
- `default-community` tells which community to use when polling exporters
- `communities` is a map from a exporter IP address to the community to
use for a exporter, overriding the default value set above,
- `poller-retries` is the number of retries on unsuccessful SNMP requests.
- `poller-timeout` tells how much time should the poller wait for an answer.
- `workers` tell how many workers to spawn to handle SNMP polling.
As flows missing interface information are discarded, persisting the
cache is useful to quickly be able to handle incoming flows. By
default, no persistent cache is configured.
## GeoIP
The GeoIP component adds source and destination country, as well as
the AS number of the source and destination IP if they are not present
in the received flows. It needs two databases using the [MaxMind DB
file format][], one for AS numbers, one for countries. If no database
is provided, the component is inactive. It accepts the following keys:
- `asn-database` tells the path to the ASN database
- `country-database` tells the path to the country database
[MaxMind DB file format]: https://maxmind.github.io/MaxMind-DB/
If the files are updated while *Akvorado* is running, they are
automatically refreshed.
## Kafka ## Kafka
@@ -207,26 +127,13 @@ kafka:
cleanup.policy: delete cleanup.policy: delete
``` ```
## ClickHouse
The ClickHouse component exposes some useful HTTP endpoints to
configure a ClickHouse database. Optionally, it will also provision
and keep up-to-date a ClickHouse database. In this case, the following
keys should be provided:
- `servers` defines the list of ClickHouse servers to connect to
- `username` is the username to use for authentication
- `password` is the password to use for authentication
- `database` defines the database to use to create tables
- `akvorado-url` defines the URL of Akvorado to be used by Clickhouse (autodetection when not specified)
## Core ## Core
The core orchestrates the remaining components. It receives the flows The core component adds some information using the GeoIP databases and
from the flow component, add some information using the GeoIP the SNMP poller, and push the resulting flow to Kafka. It is also able
databases and the SNMP poller, and push the resulting flow to Kafka. to classify exporters and interfaces into groups.
The following keys are accepted: The following configuration keys are accepted:
- `workers` key define how many workers should be spawned to process - `workers` key define how many workers should be spawned to process
incoming flows incoming flows
@@ -287,3 +194,85 @@ ClassifyProviderRegex(Interface.Description, "^Transit: ([^ ]+)", "$1")
[expr]: https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md [expr]: https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md
[from Go]: https://pkg.go.dev/regexp#Regexp.Expand [from Go]: https://pkg.go.dev/regexp#Regexp.Expand
## GeoIP
The GeoIP component adds source and destination country, as well as
the AS number of the source and destination IP if they are not present
in the received flows. It needs two databases using the [MaxMind DB
file format][], one for AS numbers, one for countries. If no database
is provided, the component is inactive. It accepts the following keys:
- `asn-database` tells the path to the ASN database
- `country-database` tells the path to the country database
[MaxMind DB file format]: https://maxmind.github.io/MaxMind-DB/
If the files are updated while *Akvorado* is running, they are
automatically refreshed.
## SNMP
Flows only include interface indexes. To associate them with an
interface name and description, SNMP is used to poll the exporter
sending each flows. A cache is maintained to avoid polling
continuously the exporters. The following keys are accepted:
- `cache-duration` tells how much time to keep data in the cache
- `cache-refresh` tells how much time to wait before updating an entry
by polling it
- `cache-check-interval` tells how often to check if cached data is
about to expire or need an update
- `cache-persist-file` tells where to store cached data on shutdown and
read them back on startup
- `default-community` tells which community to use when polling exporters
- `communities` is a map from a exporter IP address to the community to
use for a exporter, overriding the default value set above,
- `poller-retries` is the number of retries on unsuccessful SNMP requests.
- `poller-timeout` tells how much time should the poller wait for an answer.
- `workers` tell how many workers to spawn to handle SNMP polling.
As flows missing interface information are discarded, persisting the
cache is useful to quickly be able to handle incoming flows. By
default, no persistent cache is configured.
## HTTP
The builtin HTTP server serves various pages. Its configuration
supports only the `listen` key to specify the address and port to
listen. For example:
```yaml
http:
listen: 0.0.0.0:8000
```
## Web
The web interface presents the landing page of *Akvorado*. It also
embeds the documentation. It accepts only the following key:
- `grafanaurl` to specify the URL to Grafana and exposes it as
[`/grafana`](/grafana).
## ClickHouse
The ClickHouse component exposes some useful HTTP endpoints to
configure a ClickHouse database. Optionally, it will also provision
and keep up-to-date a ClickHouse database. In this case, the following
keys should be provided:
- `servers` defines the list of ClickHouse servers to connect to
- `username` is the username to use for authentication
- `password` is the password to use for authentication
- `database` defines the database to use to create tables
- `akvorado-url` defines the URL of Akvorado to be used by Clickhouse (autodetection when not specified)
## Reporting
Reporting encompasses logging and metrics. Currently, as *Akvorado* is
expected to be run inside Docker, logging is done on the standard
output and is not configurable. As for metrics, they are reported by
the HTTP component on the `/api/v0/metrics` endpoint and there is
nothing to configure either.

45
web/data/docs/03-usage.md Normal file
View File

@@ -0,0 +1,45 @@
# Usage
*Akvorado* uses a subcommand system. Each subcommand comes with its
own set of options. It is possible to get help using `akvorado
--help`.
## Starting Akvorado
`akvorado serve` starts *Akvorado* itself, allowing it to receive and
process flows. When started from a TTY, it will display logs in a
fancy way. Without a TTY, logs are output formatted as JSON.
The `--config` options allows to provide a configuration file in YAML
format. See the [configuration section](02-configuration.md) for more
information on this file.
The `--check` option will check if the provided configuration is
correct and stops here. The `--dump` option will dump the parsed
configuration, along with the default values. It should be combined
with `--check` if you don't want *Akvorado* to start.
## Exposed HTTP endpoints
The embedded HTTP server contains the following endpoints:
- [`/api/v0/metrics`](/api/v0/metrics): Prometheus metrics
- [`/api/v0/version`](/api/v0/version): *Akvorado* version
- [`/api/v0/healthcheck`](/api/v0/healthcheck): are we alive?
- [`/api/v0/flows`](/api/v0/flows?limit=1): next available flows
- [`/api/v0/schemas.json`](/api/v0/schemas.json): versioned list of protobuf schemas used to export flows
- [`/api/v0/schema-X.proto`](/api/v0/schema-1.proto): protobuf schema used to export flows
- `/api/v0/clickhouse`: various endpoints for [ClickHouse integration](04-integration.md#clickhouse)
The [`/api/v0/flows`](/api/v0/flows?limit=1) continously printed flows
sent to Kafka (using [ndjson]()). It also accepts a `limit` argument
to stops after emitting the specified number of flows. This endpoint
should not be used for anything else other than debug: it can skips
some flows and if there are several users, flows will be dispatched
between them.
[ndjson]: http://ndjson.org/
## Other commands
`akvorado version` displays the version.

View File

@@ -7,7 +7,7 @@ with ClickHouse and Grafana.
## Kafka ## Kafka
The Kafka component sends flows to Kafka. Its The Kafka component sends flows to Kafka. Its
[configuration](configuration.md#kafka) mostly needs a topic name and a list [configuration](02-configuration.md#kafka) mostly needs a topic name and a list
of brokers. It is possible to let *Akvorado* manage the topic with the of brokers. It is possible to let *Akvorado* manage the topic with the
appropriate settings (number of partitions, replication factor and appropriate settings (number of partitions, replication factor and
additional configuration entries). If the topic exists, *Akvorado* additional configuration entries). If the topic exists, *Akvorado*
@@ -30,7 +30,7 @@ ClickHouse can collect the data from Kafka. To help its configuration,
- `/api/v0/clickhouse/asns.csv` contains a CSV with the mapping - `/api/v0/clickhouse/asns.csv` contains a CSV with the mapping
between AS numbers and organization names between AS numbers and organization names
When [configured](configuration.md#clickhouse), it can also populate When [configured](02-configuration.md#clickhouse), it can also populate
the database with the appropriate tables and manages them. As a the database with the appropriate tables and manages them. As a
prerequisite, the script contained in `/api/v0/clickhouse/init.sh` prerequisite, the script contained in `/api/v0/clickhouse/init.sh`
should be executed. It is not possible for ClickHouse to fetch the should be executed. It is not possible for ClickHouse to fetch the
@@ -49,4 +49,4 @@ instances are still running an older version).
## Grafana ## Grafana
No integration is currently done for Grafana, except a reverse proxy No integration is currently done for Grafana, except a reverse proxy
configured in the [web section](configuration.md#web). configured in the [web section](02-configuration.md#web).

View File

@@ -8,12 +8,14 @@ its state and its dependencies on other components.
[Component framework in Clojure]: https://github.com/stuartsierra/component [Component framework in Clojure]: https://github.com/stuartsierra/component
![General design](../assets/images/design.svg)
Each component features the following piece of code: Each component features the following piece of code:
- A `Component` structure containing its state. - A `Component` structure containing its state.
- A `Configuration` structure containing the configuration of the - A `Configuration` structure containing the configuration of the
component. It maps to a section of [Akvorado configuration component. It maps to a section of [Akvorado configuration
file][configuration.md]. file](02-configuration.md).
- A `DefaultConfiguration` variable with the default values for the - A `DefaultConfiguration` variable with the default values for the
configuration. configuration.
- A `New()` function instantiating the component. This method takes - A `New()` function instantiating the component. This method takes
@@ -151,7 +153,7 @@ the lifecycle of the HTTP server and to provide a method to add
handlers. The web component provides the web interface of *Akvorado*. handlers. The web component provides the web interface of *Akvorado*.
Currently, this is only the documentation. Other components may expose Currently, this is only the documentation. Other components may expose
some various endpoints. They are documented in the [usage some various endpoints. They are documented in the [usage
section](usage.md). section](03-usage.md).
The daemon component handles the lifecycle of the whole application. The daemon component handles the lifecycle of the whole application.
It watches for the various goroutines (through tombs, see below) It watches for the various goroutines (through tombs, see below)
@@ -174,3 +176,32 @@ spawned by the other components and wait for signals to terminate. If
- [github.com/eapache/go-resiliency](https://github.com/eapache/go-resiliency) - [github.com/eapache/go-resiliency](https://github.com/eapache/go-resiliency)
implements several resiliency pattersn, including the breaker implements several resiliency pattersn, including the breaker
pattern. pattern.
## Future plans
In the future, we may:
- Add more information to the landing page, including some basic statistics.
- Automatically build dashboards for Grafana.[^grafana]
- Builds dashboards with [D3.js][].[^d3js]
- Buffer message to disks instead of blocking (when sending to Kafka)
or dropping (when querying the SNMP poller). We could probable just
have a system service running tcpdump dumping packets to a directory
and use that as input. This would be allow *Akvorado* to block from
end-to-end instead of trying to be realtime.
- Collect routes by integrating GoBGP. This is low priority if we
consider information from Maxmind good enough for our use.
[^grafana]: The templating system in Grafana is quite limited.
Notably, it is difficult to build different query depending on the
input fields. Grafana supports scripted dashboard, but it does not
seem to be possible to have a function build the query string.
[^d3js]: There is a [gallery][] containing many interesting examples,
including [stacked area charts][], [small multiple charts][] and
[Sankey diagrams][].
[D3.js]: https://d3js.org/
[gallery]: https://www.d3-graph-gallery.com/
[stacked area charts]: https://www.d3-graph-gallery.com/stackedarea.html
[small multiple charts]: https://www.d3-graph-gallery.com/graph/area_smallmultiple.html
[Sankey diagrams]: https://www.d3-graph-gallery.com/graph/sankey_basic.html

6
web/data/package.json Normal file
View File

@@ -0,0 +1,6 @@
{
"dependencies": {
"@mdi/font": "6.x",
"bootstrap": "^5.1.3"
}
}

View File

@@ -0,0 +1,41 @@
{{ define "title" }}Documentation{{ end }}
{{ define "stylesheets" }}
<link href="{{ .RootPath }}/assets/stylesheets/docs.css" rel="stylesheet">
{{ end }}
{{ define "content" }}
<div class="container-xxl">
<div class="row">
<div class="mb-3 col-12 col-md-3 col-lg-2">
<nav class="shadow-sm bg-light py-2 px-3 ak-docs-toc">
<strong>Documentation</strong>
<ul>
{{ range .TOC }}
<li><a href="{{ .Name }}">{{ (index .Headers 0).Title }}</a></li>
{{ end }}
</ul>
</nav>
</div>
<div class="col-12 col-md-9 col-lg-8 px-1 px-md-5 ak-docs-markdown">
{{ .Markdown }}
</div>
<div class="col-2 d-none d-lg-block">
<nav class="shadow-sm bg-light py-2 px-3 ak-docs-toc">
<strong>Table of content</strong>
<ul>
{{ $root := . }}
{{ range .TOC }}
{{ if eq .Name ($root.CurrentPath | trimPrefix "/docs/") }}
{{ range .Headers }}
{{ if ge .Level 2 }}
<li><a class="ms-{{ sub .Level 2 }} d-inline-block"
href="#{{ .ID }}">{{ .Title }}</a></li>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
</ul>
</nav>
</div>
</div>
</div>
{{ end }}

View File

@@ -0,0 +1,4 @@
{{ define "title" }}Dummy test{{ end }}
{{ define "content" }}
Hello there!
{{ end }}

View File

@@ -0,0 +1,24 @@
{{ define "base" }}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="{{ .RootPath }}/assets/stylesheets/bootstrap.min.css" rel="stylesheet">
<link href="{{ .RootPath }}/assets/stylesheets/materialdesignicons.min.css" rel="stylesheet">
<link href="{{ .RootPath }}/assets/stylesheets/akvorado.css" rel="stylesheet">
{{ block "stylesheets" . }}{{ end }}
<link href="{{ .RootPath }}/assets/images/akvorado.svg" rel="icon">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{{ template "title" . }}</title>
</head>
<body>
{{ template "navigation.html" . }}
<main class="container-fluid pt-4">
{{ template "content" . }}
</main>
</body>
<script src="{{ .RootPath }}/assets/javascript/bootstrap.bundle.min.js"></script>
{{ block "scripts" . }}{{ end }}
</script>
</html>
{{ end }}

View File

@@ -0,0 +1,29 @@
<header class="navbar navbar-expand-sm navbar-light py-1 shadow-sm ak-navbar">
<nav class="container-xxl flex-wrap flex-sm-nowrap" aria-="Main navigation">
<a class="navbar-brand p-0 me-2"
href="{{ .RootPath }}"
aria-label="Akvorado">
<img alt="Akvorado logo"
height="40"
src="{{ .RootPath }}/assets/images/akvorado.svg">
Akvorado
</a>
<button class="navbar-toggler collapsed" type="button"
data-bs-toggle="collapse" data-bs-target="#akNavbar"
aria-controls="akNavbar" aria-expanded="false" aria-label="Toggle navigation">
<i class="mdi mdi-menu"></i>
</button>
<div class="navbar-collapse collapse" id="akNavbar">
<ul class="navbar-nav flex-row flex-wrap pt-2 py-sm-0 ms-sm-auto">
<li class="navitem col-6 col-sm-auto">
<a class="nav-link pt-2{{ if eq .CurrentPath "/" }} active{{ end }}"
href="{{ .RootPath }}"><i class="mdi mdi-home"> </i>Home</a>
</li>
<li class="navitem col-6 col-sm-auto">
<a class="nav-link pt-2{{ if .CurrentPath | hasPrefix "/docs" }} active{{ end }}"
href="{{ .RootPath }}/docs/intro"><i class="mdi mdi-book-open-variant"> </i>Docs</a>
</li>
</ul>
</div>
</nav>
</header>

13
web/data/yarn.lock Normal file
View File

@@ -0,0 +1,13 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@mdi/font@6.x":
version "6.6.96"
resolved "https://registry.yarnpkg.com/@mdi/font/-/font-6.6.96.tgz#4eee6faee5f44d3ec401d354fb95775cd6699575"
integrity sha512-FbcvG9z17hwZ7IwX5XeOR1UYGoLq+gTKq6XNPvJFuCpn599GdiPCJbAmmDBJb+jMYXjKYr0lCxfouWGxDA82sA==
bootstrap@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34"
integrity sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==

190
web/docs.go Normal file
View File

@@ -0,0 +1,190 @@
package web
import (
"bytes"
"embed"
"fmt"
"html/template"
"io/fs"
"io/ioutil"
"net/http"
"regexp"
"strings"
"github.com/yuin/goldmark"
highlighting "github.com/yuin/goldmark-highlighting"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
var (
//go:embed data/docs
embeddedDocs embed.FS
internalLinkRegexp = regexp.MustCompile("^(([0-9]+)-([a-z]+).md)(#.*|$)")
)
// Header describes a document header.
type Header struct {
Level int
ID string
Title string
}
// DocumentTOC describes the TOC of a document
type DocumentTOC struct {
Name string
Headers []Header
}
type templateDocData struct {
templateBaseData
Markdown template.HTML
TOC []DocumentTOC
}
func (c *Component) docsHandlerFunc(w http.ResponseWriter, req *http.Request) {
docs := c.embedOrLiveFS(embeddedDocs, "data/docs")
rpath := strings.TrimPrefix(req.URL.Path, "/docs/")
rpath = strings.Trim(rpath, "/")
var markdown []byte
toc := []DocumentTOC{}
// Find right file and compute ToC
entries, err := fs.ReadDir(docs, ".")
if err != nil {
c.r.Err(err).Msg("unable to list documentation files")
http.Error(w, "Unable to get documentation files.", http.StatusInternalServerError)
return
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
matches := internalLinkRegexp.FindStringSubmatch(entry.Name())
if matches == nil {
continue
}
f, err := http.FS(docs).Open(entry.Name())
if err != nil {
c.r.Err(err).Str("path", entry.Name()).Msg("unable to open documentation file")
continue
}
// Markdown rendering to build ToC
content, _ := ioutil.ReadAll(f)
f.Close()
if matches[3] == rpath {
// That's the one we need to do final rendering on.
markdown = content
}
tocLogger := &tocLogger{}
md := goldmark.New(
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
parser.WithASTTransformers(
util.Prioritized(tocLogger, 500),
),
),
)
buf := &bytes.Buffer{}
if err = md.Convert(content, buf); err != nil {
c.r.Err(err).Str("path", rpath).Msg("unable to render markdown document")
continue
}
toc = append(toc, DocumentTOC{
Name: matches[3],
Headers: tocLogger.headers,
})
}
if markdown == nil {
http.Error(w, "Document not found.", http.StatusNotFound)
return
}
md := goldmark.New(
goldmark.WithExtensions(
extension.Footnote,
extension.Typographer,
highlighting.Highlighting,
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
parser.WithASTTransformers(
util.Prioritized(&internalLinkTransformer{}, 500),
),
),
)
buf := &bytes.Buffer{}
if err = md.Convert(markdown, buf); err != nil {
c.r.Err(err).Str("path", rpath).Msg("unable to render markdown document")
http.Error(w, "Unable to render document.", http.StatusInternalServerError)
return
}
w.Header().Set("Cache-Control", "max-age=300")
c.renderTemplate(w, "docs.html", templateDocData{
templateBaseData: templateBaseData{
RootPath: "..",
CurrentPath: req.URL.Path,
},
Markdown: template.HTML(buf.String()),
TOC: toc,
})
}
type internalLinkTransformer struct{}
func (r *internalLinkTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
replaceLinks := func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
switch node := n.(type) {
case *ast.Link:
matches := internalLinkRegexp.FindStringSubmatch(string(node.Destination))
if matches != nil {
node.Destination = []byte(fmt.Sprintf("%s%s", matches[3], matches[4]))
}
}
return ast.WalkContinue, nil
}
ast.Walk(node, replaceLinks)
}
type tocLogger struct {
headers []Header
}
func (r *tocLogger) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
r.headers = []Header{}
logHeaders := func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
switch node := n.(type) {
case *ast.Heading:
id, ok := n.AttributeString("id")
if ok {
var title []byte
lastIndex := node.Lines().Len() - 1
if lastIndex > -1 {
lastLine := node.Lines().At(lastIndex)
title = lastLine.Value(reader.Source())
}
if title != nil {
r.headers = append(r.headers, Header{
ID: string(id.([]uint8)),
Level: node.Level,
Title: string(title),
})
}
}
}
return ast.WalkContinue, nil
}
ast.Walk(node, logHeaders)
}

44
web/docs_test.go Normal file
View File

@@ -0,0 +1,44 @@
package web
import (
"fmt"
"io/ioutil"
netHTTP "net/http"
"strings"
"testing"
"akvorado/http"
"akvorado/reporter"
)
func TestServeDocs(t *testing.T) {
for _, live := range []bool{false, true} {
name := "livefs"
if !live {
name = "embeddedfs"
}
t.Run(name, func(t *testing.T) {
r := reporter.NewMock(t)
h := http.NewMock(t, r)
_, err := New(r, Configuration{
ServeLiveFS: live,
}, Dependencies{HTTP: h})
if err != nil {
t.Fatalf("New() error:\n%+v", err)
}
resp, err := netHTTP.Get(fmt.Sprintf("http://%s/docs/usage", h.Address))
if err != nil {
t.Fatalf("GET /docs/usage:\n%+v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Errorf("GET /docs/usage: got status code %d, not 200", resp.StatusCode)
}
body, _ := ioutil.ReadAll(resp.Body)
if strings.Contains(string(body), "configuration.md") {
t.Errorf("GET /docs/usage: contains %q while it should not", "configuration.md")
}
})
}
}

View File

@@ -2,8 +2,8 @@
package web package web
import ( import (
"embed"
"fmt" "fmt"
"html/template"
"io/fs" "io/fs"
"log" "log"
netHTTP "net/http" netHTTP "net/http"
@@ -13,21 +13,24 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"sync"
"github.com/rs/zerolog"
"gopkg.in/tomb.v2"
"akvorado/http" "akvorado/http"
"akvorado/reporter" "akvorado/reporter"
"github.com/rs/zerolog"
) )
//go:embed data
var rootSite embed.FS
// Component represents the web component. // Component represents the web component.
type Component struct { type Component struct {
r *reporter.Reporter r *reporter.Reporter
d *Dependencies d *Dependencies
t tomb.Tomb
config Configuration config Configuration
templates map[string]*template.Template
templatesLock sync.RWMutex
} }
// Dependencies define the dependencies of the web component. // Dependencies define the dependencies of the web component.
@@ -42,20 +45,11 @@ func New(reporter *reporter.Reporter, config Configuration, dependencies Depende
d: &dependencies, d: &dependencies,
config: config, config: config,
} }
if err := c.loadTemplates(); err != nil {
var data fs.FS return nil, err
if config.ServeLiveFS {
_, src, _, _ := runtime.Caller(0)
data = os.DirFS(filepath.Join(path.Dir(src), "data"))
} else {
var err error
data, err = fs.Sub(rootSite, "data")
if err != nil {
return nil, fmt.Errorf("unable to get embedded website: %w", err)
}
} }
c.d.HTTP.AddHandler("/", netHTTP.FileServer(netHTTP.FS(data)))
// Grafana proxy
if c.config.GrafanaURL != "" { if c.config.GrafanaURL != "" {
// Provide a proxy for Grafana // Provide a proxy for Grafana
url, err := url.Parse(config.GrafanaURL) url, err := url.Parse(config.GrafanaURL)
@@ -77,5 +71,49 @@ func New(reporter *reporter.Reporter, config Configuration, dependencies Depende
c.d.HTTP.AddHandler("/grafana/", proxyHandler) c.d.HTTP.AddHandler("/grafana/", proxyHandler)
} }
c.d.HTTP.AddHandler("/docs/", netHTTP.HandlerFunc(c.docsHandlerFunc))
c.d.HTTP.AddHandler("/assets/", netHTTP.HandlerFunc(c.assetsHandlerFunc))
return &c, nil return &c, nil
} }
// Start starts the web component.
func (c *Component) Start() error {
c.r.Info().Msg("starting web component")
if err := c.watchTemplates(); err != nil {
return err
}
c.t.Go(func() error {
select {
case <-c.t.Dying():
return nil
}
})
return nil
}
// Stop stops the web component.
func (c *Component) Stop() error {
c.r.Info().Msg("stopping web component")
defer c.r.Info().Msg("web component stopped")
c.t.Kill(nil)
return c.t.Wait()
}
// embedOrLiveFS returns a subset of the provided embedded filesystem,
// except if the component is configured to use the live filesystem.
// Then, it returns the provided tree.
func (c *Component) embedOrLiveFS(embed fs.FS, p string) fs.FS {
var fileSystem fs.FS
if c.config.ServeLiveFS {
_, src, _, _ := runtime.Caller(0)
fileSystem = os.DirFS(filepath.Join(path.Dir(src), p))
} else {
var err error
fileSystem, err = fs.Sub(embed, p)
if err != nil {
panic(err)
}
}
return fileSystem
}

View File

@@ -47,31 +47,3 @@ func TestProxy(t *testing.T) {
t.Errorf("GET /grafana/test (-got, +want):\n%s", diff) t.Errorf("GET /grafana/test (-got, +want):\n%s", diff)
} }
} }
func TestStaticFiles(t *testing.T) {
for _, live := range []bool{false, true} {
name := "livefs"
if !live {
name = "embeddedfs"
}
t.Run(name, func(t *testing.T) {
r := reporter.NewMock(t)
h := http.NewMock(t, r)
_, err := New(r, Configuration{
ServeLiveFS: live,
}, Dependencies{HTTP: h})
if err != nil {
t.Fatalf("New() error:\n%+v", err)
}
resp, err := netHTTP.Get(fmt.Sprintf("http://%s/install.html", h.Address))
if err != nil {
t.Fatalf("GET /install.html:\n%+v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Errorf("GET /install.html: got status code %d, not 200", resp.StatusCode)
}
})
}
}

153
web/templates.go Normal file
View File

@@ -0,0 +1,153 @@
package web
import (
"akvorado/reporter"
"bytes"
"embed"
"fmt"
"html/template"
"io"
"io/fs"
"net/http"
"path"
"path/filepath"
"runtime"
"time"
"github.com/Masterminds/sprig"
"github.com/fsnotify/fsnotify"
)
//go:embed data/templates
var embeddedTemplates embed.FS
// baseData is the data to pass for all templates.
type templateBaseData struct {
RootPath string
CurrentPath string
}
// loadTemplates reload the templates.
func (c *Component) loadTemplates() error {
mainTemplate, err := template.
New("main").
Option("missingkey=error").
Funcs(sprig.FuncMap()).
Parse(`{{define "main" }}{{ template "base" . }}{{ end }}`)
if err != nil {
c.r.Err(err).Msg("unable to create main template")
return fmt.Errorf("unable to create main template: %w", err)
}
layoutFiles := c.embedOrLiveFS(embeddedTemplates, "data/templates/layout")
templateFiles := c.embedOrLiveFS(embeddedTemplates, "data/templates")
compiled := make(map[string]*template.Template)
entries, err := fs.ReadDir(templateFiles, ".")
if err != nil {
c.r.Err(err).Msg("unable to list template files")
return fmt.Errorf("unable to list template files: %w", err)
}
for _, tpl := range entries {
if tpl.IsDir() {
continue
}
template, err := mainTemplate.Clone()
if err != nil {
c.r.Err(err).Msg("unable to clone main template")
return fmt.Errorf("unable to clone main template: %w", err)
}
f, err := templateFiles.Open(tpl.Name())
if err != nil {
c.r.Err(err).Str("template", tpl.Name()).Msg("unable to open template")
return fmt.Errorf("unable to open template %q: %w", tpl.Name(), err)
}
content, err := io.ReadAll(f)
if err != nil {
f.Close()
c.r.Err(err).Str("template", tpl.Name()).Msg("unable to read template")
return fmt.Errorf("unable to read template %q: %w", tpl.Name(), err)
}
f.Close()
template, err = template.Parse(string(content))
if err != nil {
c.r.Err(err).Str("template", tpl.Name()).Msg("unable to parse template")
return fmt.Errorf("unable to parse template %q: %w", tpl.Name(), err)
}
template, err = template.ParseFS(layoutFiles, "*.html")
if err != nil {
c.r.Err(err).Msg("unable to parse layout templates")
return fmt.Errorf("unable to parse layout templates: %w", err)
}
compiled[tpl.Name()] = template
}
c.templatesLock.Lock()
c.templates = compiled
c.templatesLock.Unlock()
return nil
}
// renderTemplate render the specified template
func (c *Component) renderTemplate(w http.ResponseWriter, name string, data interface{}) {
c.templatesLock.RLock()
tmpl, ok := c.templates[name]
c.templatesLock.RUnlock()
if !ok {
c.r.Error().Str("template", name).Msg("template not found")
http.Error(w, fmt.Sprintf("No template %q found.", name), http.StatusNotFound)
return
}
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, data); err != nil {
c.r.Err(err).Str("template", name).Msg("error while rendering template")
http.Error(w, fmt.Sprintf("Error while rendering %q.", name), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
buf.WriteTo(w)
}
// watchTemplates monitor changes in template directories and reload them
func (c *Component) watchTemplates() error {
if !c.config.ServeLiveFS {
return nil
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
c.r.Err(err).Msg("cannot setup watcher for templates")
return fmt.Errorf("cannot setup watcher: %w", err)
}
for _, dir := range []string{"templates", "templates/layout"} {
_, base, _, _ := runtime.Caller(0)
dir = filepath.Join(path.Dir(base), "data", dir)
if err := watcher.Add(dir); err != nil {
c.r.Err(err).Str("directory", dir).Msg("cannot watch template directory")
return fmt.Errorf("cannot watch template directory %q: %w", dir, err)
}
}
c.t.Go(func() error {
defer watcher.Close()
errLogger := c.r.Sample(reporter.BurstSampler(10*time.Second, 1))
timer := time.NewTimer(100 * time.Millisecond)
for {
select {
case <-c.t.Dying():
return nil
case err := <-watcher.Errors:
errLogger.Err(err).Msg("error from watcher")
case event := <-watcher.Events:
if event.Op&(fsnotify.Write|fsnotify.Create) == 0 {
continue
}
timer.Stop()
timer.Reset(500 * time.Millisecond)
case <-timer.C:
c.r.Info().Msg("reload templates")
c.loadTemplates() // errors are ignored
}
}
})
return nil
}

56
web/templates_test.go Normal file
View File

@@ -0,0 +1,56 @@
package web
import (
"net/http/httptest"
"strings"
"testing"
"time"
"akvorado/http"
"akvorado/reporter"
)
func TestTemplate(t *testing.T) {
for _, live := range []bool{false, true} {
name := "livefs"
if !live {
name = "embeddedfs"
}
t.Run(name, func(t *testing.T) {
r := reporter.NewMock(t)
c, err := New(r, Configuration{
ServeLiveFS: live,
}, Dependencies{HTTP: http.NewMock(t, r)})
if err != nil {
t.Fatalf("New() error:\n%+v", err)
}
if err := c.Start(); err != nil {
t.Fatalf("Start() error:\n%+v", err)
}
defer func() {
if err := c.Stop(); err != nil {
t.Fatalf("Stop() error:\n%+v", err)
}
}()
w := httptest.NewRecorder()
c.renderTemplate(w, "dummy.html", templateBaseData{
RootPath: ".",
})
if w.Code != 200 {
t.Errorf("renderTemplate() code was %d, expected 200", w.Code)
}
body := strings.TrimSpace(w.Body.String())
if !strings.HasPrefix(body, "<!doctype html>") {
t.Errorf("renderTemplate() body should contain <!doctype html>, got:\n%s",
body)
}
if live && !testing.Short() {
// Wait for refresh of templates to happen.
time.Sleep(200 * time.Millisecond)
}
})
}
}