mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
web: frontend using Bootstrap
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
Dockerfile
|
Dockerfile
|
||||||
|
node_modules/
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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/
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
12
Dockerfile
12
Dockerfile
@@ -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
|
||||||
|
|||||||
17
Makefile
17
Makefile
@@ -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,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 |
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
# Design
|
|
||||||
|
|
||||||
<figure markdown>
|
|
||||||
{ 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
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
---
|
|
||||||
hide:
|
|
||||||
- navigation
|
|
||||||
- toc
|
|
||||||
---
|
|
||||||
|
|
||||||
# Akvorado { style=display:none }
|
|
||||||
|
|
||||||
{ .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>
|
|
||||||
@@ -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/
|
|
||||||
@@ -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
11
go.mod
@@ -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
21
go.sum
@@ -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=
|
||||||
|
|||||||
66
mkdocs.yml
66
mkdocs.yml
@@ -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
39
web/assets.go
Normal 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
43
web/assets_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
440
web/data/assets/images/akvorado.svg
Normal file
440
web/data/assets/images/akvorado.svg
Normal 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 |
4
web/data/assets/images/design.svg
Normal file
4
web/data/assets/images/design.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 217 KiB |
10
web/data/assets/stylesheets/akvorado.css
Normal file
10
web/data/assets/stylesheets/akvorado.css
Normal 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;
|
||||||
|
}
|
||||||
10
web/data/assets/stylesheets/docs.css
Normal file
10
web/data/assets/stylesheets/docs.css
Normal 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
46
web/data/docs/00-intro.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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.
|
||||||
@@ -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
45
web/data/docs/03-usage.md
Normal 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.
|
||||||
@@ -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).
|
||||||
@@ -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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
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
6
web/data/package.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@mdi/font": "6.x",
|
||||||
|
"bootstrap": "^5.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
41
web/data/templates/docs.html
Normal file
41
web/data/templates/docs.html
Normal 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 }}
|
||||||
4
web/data/templates/dummy.html
Normal file
4
web/data/templates/dummy.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{{ define "title" }}Dummy test{{ end }}
|
||||||
|
{{ define "content" }}
|
||||||
|
Hello there!
|
||||||
|
{{ end }}
|
||||||
24
web/data/templates/layout/base.html
Normal file
24
web/data/templates/layout/base.html
Normal 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 }}
|
||||||
29
web/data/templates/layout/navigation.html
Normal file
29
web/data/templates/layout/navigation.html
Normal 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
13
web/data/yarn.lock
Normal 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
190
web/docs.go
Normal 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
44
web/docs_test.go
Normal 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")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
74
web/root.go
74
web/root.go
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
153
web/templates.go
Normal 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
56
web/templates_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user