Compare commits

...

72 Commits

Author SHA1 Message Date
b319e89e41 Release 2.15.0 2024-09-23 03:32:01 +03:00
b3d32c6fc4 build: speedup pacman 2024-09-23 03:30:17 +03:00
91c2aef931 website: add logo to api docs 2024-09-23 02:39:54 +03:00
3ad0037fa9 docs: update configuration references in docs 2024-09-22 15:16:34 +03:00
f5d415ab4f docs: add logo 2024-09-22 14:21:01 +03:00
b002db1148 feat: drop explicit makepkg usage (#134)
* generate filenames without using makepkg

* pkgbuild parser impl

* completely remove makepkg calls

* simplify typed get

* try to improve parser

* docs and recipes updatte

* never raise keyerror instead return empty string

* udpate tests

* add support of array expansion

* docs update

* tests update

* handle quoted control sequences correctly

* expand bash

* allow packages without package function

* docs update

* add moroe tests

* small improovements

* support escaped arrays and functions
2024-09-21 03:57:22 +03:00
393104f9fa type: ignore too-many-positional-arguments 2024-09-20 23:22:33 +03:00
b9f39e0d99 chore: refresh icons 2024-09-20 03:29:18 +03:00
990397e1cb Revert "fix: update Repo.init to the latest pacman release"
This reverts commit d30d512eb6.
2024-09-20 01:48:09 +03:00
300713f5d5 fix: limit amount of fetches used for changes
The issue appears in case if - somehow - unknown commit sha has been
stored. In this scenario it would try to fetch infinitely
2024-09-20 01:48:03 +03:00
9a17f19f7b feat: calculate changes on package addition as well 2024-09-20 01:48:03 +03:00
3ff1bf473c fix: do not treat cached vcs packages as local 2024-09-20 01:47:58 +03:00
50cd71b954 feat: calculate and store changes for each update 2024-09-17 15:01:45 +03:00
f81ebe6c3c docs: improve class init docs 2024-09-15 15:13:54 +03:00
1d85a61cc4 feat: get rid of jquery (#133) 2024-09-05 02:26:52 +03:00
689de82139 build: make cerberus dependency optional 2024-09-04 22:28:25 +03:00
5b9f35220f feat: implement stats subcommand (#132) 2024-09-04 22:28:25 +03:00
8fc4d7b4a5 feat: allow filter events by timestamp 2024-09-04 22:28:25 +03:00
cedf18ac7a chore: add rss generation to samples 2024-09-04 22:28:25 +03:00
164b6d7956 feat: add event log and update chart to package info modal 2024-09-04 22:28:25 +03:00
27e595cdf4 feat: remove duplicates from the toast 2024-09-04 22:28:25 +03:00
020560d341 refactor: simplify Validator class 2024-09-04 22:28:25 +03:00
cdef67986b feat: allow cross reference in the configuration (#131) 2024-09-04 22:28:25 +03:00
dddcd0bfce feat: implement rss generation (#130) 2024-09-04 22:28:25 +03:00
a0784b7af1 feat: add ability to log sql statements 2024-09-04 22:28:25 +03:00
4c4c9b2bfd feat: serve logs and events from the newest to oldest, but keep the
ordering

So basically initial implementation, with limit=1, would emit the oldest
record in series. New implementation will return the most recent one
instead

The response is still sorted by ascension
2024-09-04 22:28:25 +03:00
5c34c051cb feat: log package update events 2024-09-04 22:28:25 +03:00
4fa44b0532 refactor: allow event to receive keyword arguments
This change also replaces the dataclass implementation of the class to
custom one
2024-09-04 22:28:25 +03:00
f167ce7d3b feat: add timer for metrics purposes 2024-09-04 22:28:25 +03:00
950b9e4289 docs: update booleans in docs 2024-09-04 22:28:25 +03:00
264aeb7150 feat: implement audit log tables and methods (#129) 2024-09-04 22:28:25 +03:00
be7169c5df feat: replace scan paths options to single one
It has been found that previous system didn't allow to configure
specific cases (e.g. a whitelisted directory inside /usr/lib/cmake). The
current solution replaces two options to single one, which also allows a
regular expressions

Also PackageArchive class has been moved to core package, because it is
more about service rather than model
2024-09-04 22:25:54 +03:00
9c1e9ecbdc Release 2.14.1 2024-09-04 22:01:04 +03:00
4b2f6bbee9 bug: fix removal of the packages
It has been broken since reporter improvements, because it effectivelly
1) didn't call remove functions in database
2) used empty repository identifier for web service

With those changes it also raises exception when you try to call id on
empty identifier
2024-09-04 21:50:33 +03:00
fd8c8a00d0 chore: small contributing guide update 2024-09-04 21:49:31 +03:00
eaf1984eb3 refactor: fix some IDE warnings 2024-09-04 21:49:31 +03:00
794dddccd9 build: update pytest configuration to suppress deprecation warnings 2024-09-04 21:49:31 +03:00
7bd7f95f76 Release 2.14.0 2024-08-23 14:37:05 +03:00
375374c396 docs: improve waiter classes docs 2024-08-23 14:33:07 +03:00
d1ad5ecc11 feat: add ability to suppress git hints
It can be done by setting options in command. The commit author/email is
also now using this logic
2024-08-23 14:33:07 +03:00
1eb4d8e47f feat: add blacklisted paths to implicit dependencies processing
It has been found that in some cases additional packages have been added
as dependencies, like usr/share/applications, usr/lib/cmake, etc

This commit adds an ability to blacklist specific paths from processing
2024-08-23 14:33:07 +03:00
0861548b56 docs: split faq into multiple files 2024-08-20 16:44:40 +03:00
e9e4172063 feat: add support of pam authentication
Add naive implementation of user password check by calling su command.
Also change some authentication method to require username to be string
instead of optional string
2024-08-20 16:44:40 +03:00
beb6156795 fix: print current and updated version correctly
The issue appears in case if versions ar the same (e.g. rebuild); in
this case printer doesn't increment version as builder does.

Also util has been renamed to utils, keeping backward compatibiltiy
2024-08-16 16:24:11 +03:00
dbfb460557 feat: optimize archive reading
Instead of trying to load every database and look for files, this commit
introduces the optimization in which, the service loads packages first,
groups them by database and load files later.

In some cases it significantly descreases times for loading files
2024-08-14 17:07:10 +03:00
f7f76c4119 fix: explicitly process list of packages
Small workaround to remove debug packages from being processed
2024-08-14 17:07:10 +03:00
88ee300b9e fix: remove trailit slash when loading packages files from a database 2024-08-14 17:07:10 +03:00
6f30c687c2 fix: skip debug packages as well 2024-08-14 17:07:10 +03:00
c023ebe165 docs: update documentation for implicit dependencies resolution 2024-08-14 17:07:10 +03:00
54b99cacfd feat: remove excess dependencies leaves (#128)
This mr improves implicit dependencies processing by reducing tree leaves by using the following algorithm:

* remove paths which belong to any base package
* remove packages which are (opt)dependencies of one of the package which provides same path. It also tries to handle circular dependencies by excluding them from being "satisfied"
* remove packages which are already satisfied by any children path
2024-08-14 17:07:10 +03:00
4f5166ff25 feat: improve lock mechanisms
* improve lock mechanisms

* use /run/ahriman for sockett

* better water
2024-08-14 17:07:10 +03:00
c8afcbf36a feat: implement local reporter mode (#126)
* implement local reporter mode

* simplify watcher class

* review changes

* do not update unknown status

* allow empty key patches via api

* fix some pylint warnings in tests
2024-08-14 17:07:10 +03:00
2b9880bd3c feat: allow to use simplified keys for context
Initial implementation requires explicit context key name to be set.
Though it is still useful sometimes (e.g. if there should be two
variables with the same type), in the most used scenarios internally
only type is required. This commit extends set and get methods to allow
to construct ContextKey from type directly

Also it breaks old keys, since - in order to reduce amount of possible
mistakes - internal classes uses this generation method
2024-08-14 17:07:10 +03:00
3be5cdafe8 feat: add abillity to check broken dependencies (#122)
* implement elf dynamic linking check

* load local database too in pacman wrapper
2024-08-14 17:07:10 +03:00
668be41c3e type: drop MiddlewareType in favour of Middleware builtin 2024-08-14 17:07:10 +03:00
3353daec6d type: fix mypy warn for fresh unixsocket release 2024-08-14 17:07:10 +03:00
eef4d2dd98 type: remove another unused mypy directive 2024-08-14 17:07:10 +03:00
b15161554e build: use requests-unixsocket2 fork
Since requests-2.32.0, the http+unix url scheme is brokek, check
https://github.com/msabramo/requests-unixsocket/issues/73 for more
details
2024-08-14 17:07:10 +03:00
bb4a0d75fc Release 2.13.8 2024-05-12 11:53:19 +03:00
bca0df41d1 fix: drop integrity check for javascript
It has been added to improve security, however, it changes over time for
no reason ¯\_(ツ)_/¯ I guess either cdn was hacked or fuck js
2024-05-12 11:49:12 +03:00
07b77be6b8 Release 2.13.7 2024-05-09 13:26:40 +03:00
2b33510ada fix: parse array variable from command 2024-05-09 13:21:42 +03:00
6d05389639 Release 2.13.6 2024-05-05 21:59:30 +03:00
daf9841717 fix: update integrity checksums for momentjs and daterangepicker 2024-05-05 21:17:30 +03:00
0d243a781a refactor: update code to the latest python (3.12+) 2024-05-05 21:17:30 +03:00
cf2e66a934 fix: remove debug packages together with normal ones (#124) 2024-05-05 21:17:30 +03:00
f01f35238d Release 2.13.5 2024-04-04 13:33:03 +03:00
d30d512eb6 fix: update Repo.init to the latest pacman release 2024-04-04 13:16:05 +03:00
0437f90e5a build: install base-devel package 2024-04-04 13:16:03 +03:00
3cab65855a fix: lazy web component initialization
In some cases (probably slow internet) in place initialization can cause
exception, because elements are not available yet. This commit moves
events initialization to $()
2024-04-04 13:14:17 +03:00
ecfb615f97 feat: add ability to disable debug packages distribution
The feature is implemented as supplying !debug option to makepkg when
generating package list. In this case debug packages still will be
built, however, they will not be added to the repository
2024-04-04 13:14:17 +03:00
243983ee64 docs: update docs 2024-02-10 03:12:09 +02:00
377 changed files with 29038 additions and 16059 deletions

View File

@ -8,19 +8,17 @@ set -ex
# install dependencies
echo -e '[arcanisrepo]\nServer = https://repo.arcanis.me/$arch\nSigLevel = Never' | tee -a /etc/pacman.conf
# refresh the image
pacman -Syu --noconfirm
pacman -Syyu --noconfirm
# main dependencies
pacman -Sy --noconfirm devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-srcinfo python-systemd sudo
pacman -S --noconfirm devtools git pyalpm python-inflection python-passlib python-pyelftools python-requests python-systemd sudo
# make dependencies
pacman -Sy --noconfirm python-build python-flit python-installer python-tox python-wheel
pacman -S --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel
# optional dependencies
if [[ -z $MINIMAL_INSTALL ]]; then
# VCS support
pacman -Sy --noconfirm breezy darcs mercurial subversion
# web server
pacman -Sy --noconfirm python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja
pacman -S --noconfirm python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja
# additional features
pacman -Sy --noconfirm gnupg python-boto3 rsync
pacman -S --noconfirm gnupg python-boto3 python-cerberus python-matplotlib rsync
fi
# FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container
cp "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn"
@ -36,21 +34,24 @@ sudo -u nobody -- makepkg --packagelist | grep -v -- -debug- | pacman -U --nocon
# create machine-id which is required by build tools
systemd-machine-id-setup
# remove unused dependencies
pacman -Qdtq | pacman -Rscn --noconfirm -
# initial setup command as root
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot <ahriman@example.com>" "${WEB_ARGS[@]}"
# validate configuration
ahriman service-config-validate --exit-code
# enable services
systemctl enable ahriman-web
systemctl enable ahriman@x86_64-github.timer
if [[ -z $MINIMAL_INSTALL ]]; then
# validate configuration
ahriman service-config-validate --exit-code
# run web service (detached)
sudo -u ahriman -- ahriman web &
WEB_PID=$!
fi
# add the first package
sudo -u ahriman -- ahriman package-add --now ahriman
sudo -u ahriman -- ahriman --log-handler console package-add --now ahriman
# check if package was actually installed
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
# run package check

View File

@ -4,7 +4,7 @@
set -ex
# install dependencies
pacman --noconfirm -Syu base-devel python-tox
pacman --noconfirm -Syyu base-devel python-tox
# run test and check targets
tox

View File

@ -82,6 +82,7 @@ limit-inference-results=100
# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
load-plugins=pylint.extensions.docparams,
pylint.extensions.bad_builtin,
definition_order,
import_order,
@ -131,6 +132,8 @@ attr-naming-style=snake_case
# style.
#attr-rgx=
bad-functions=print,
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
@ -445,6 +448,7 @@ disable=raw-checker-failed,
too-many-arguments,
duplicate-code,
cyclic-import,
too-many-positional-arguments,
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

View File

@ -3,7 +3,7 @@ version: 2
build:
os: ubuntu-20.04
tools:
python: "3.11"
python: "3.12"
python:
install:
@ -12,6 +12,7 @@ python:
extra_requirements:
- docs
- s3
- validator
- web
formats:

View File

@ -36,6 +36,7 @@ Again, the most checks can be performed by `tox` command, though some additional
Notes:
Very important note about this function
Probably multi-line
Args:
argument(str): an argument. This argument has
@ -70,6 +71,7 @@ Again, the most checks can be performed by `tox` command, though some additional
Attributes:
CLAZZ_ATTRIBUTE(int): (class attribute) a brand-new class attribute
instance_attribute(str): an instance attribute
with the long description
Examples:
Very informative class usage example, e.g.::
@ -82,8 +84,6 @@ Again, the most checks can be performed by `tox` command, though some additional
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""
default constructor
Args:
*args(Any): positional arguments
**kwargs(Any): keyword arguments
@ -91,8 +91,10 @@ Again, the most checks can be performed by `tox` command, though some additional
self.instance_attribute = ""
```
Note missing comment for the `__init__` method, which is the special case.
* Type annotations are the must, even for local functions. For the function argument `self` (for instance methods) and `cls` (for class methods) should not be annotated.
* For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typinng.Optional` (e.g. `str | None` instead of `Optional[str]`).
* For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typing.Optional` (e.g. `str | None` instead of `Optional[str]`).
* `classmethod` should (almost) always return `Self`. In case of mypy warning (e.g. if there is a branch in which function doesn't return the instance of `cls`) consider using `staticmethod` instead.
* Recommended order of function definitions in class:
@ -132,7 +134,7 @@ Again, the most checks can be performed by `tox` command, though some additional
* For any path interactions `pathlib.Path` must be used.
* Configuration interactions must go through `ahriman.core.configuration.Configuration` class instance.
* In case if class load requires some actions, it is recommended to create class method which can be used for class instantiating.
* The code must follow the exception safety, unless it is explicitly asked by end user. It means that most exceptions must be handled and printed to log, no other actions must be done (e.g. raising another exception).
* The most (expected) exceptions must be handled and printed to log, allowing service to continue work. However, fatal and (in some cases) unexpected exceptions may lead to the application termination.
* Exceptions without parameters should be raised without parentheses, e.g.:
```python

View File

@ -25,18 +25,48 @@ RUN echo "[multilib]" >> "/etc/pacman.conf" && \
echo "Include = /etc/pacman.d/mirrorlist" >> "/etc/pacman.conf"
## refresh packages, install sudo and install packages for building
RUN pacman -Syu --noconfirm sudo && \
pacman -Sy --noconfirm --asdeps fakeroot python-tox
pacman -S --noconfirm --asdeps fakeroot python-tox
## create build user
RUN useradd -m -d "/home/build" -s "/usr/bin/nologin" build && \
echo "build ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/build"
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
## install package dependencies
## darcs is not installed by reasons, because it requires a lot haskell packages which dramatically increase image size
RUN pacman -Sy --noconfirm --asdeps devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-srcinfo && \
pacman -Sy --noconfirm --asdeps python-build python-flit python-installer python-wheel && \
pacman -Sy --noconfirm --asdeps breezy git mercurial python-aiohttp python-boto3 python-cryptography python-jinja python-requests-unixsocket python-systemd rsync subversion && \
runuser -u build -- install-aur-package python-aioauth-client python-aiohttp-apispec-git python-aiohttp-cors \
python-aiohttp-jinja2 python-aiohttp-session python-aiohttp-security
RUN pacman -S --noconfirm --asdeps \
devtools \
git \
pyalpm \
python-inflection \
python-passlib \
python-pyelftools \
python-requests \
&& \
pacman -S --noconfirm --asdeps \
base-devel \
python-build \
python-flit \
python-installer \
python-wheel \
&& \
pacman -S --noconfirm --asdeps \
git \
python-aiohttp \
python-boto3 \
python-cerberus \
python-cryptography \
python-jinja \
python-matplotlib \
python-systemd \
rsync \
&& \
runuser -u build -- install-aur-package \
python-aioauth-client \
python-webargs \
python-aiohttp-apispec-git \
python-aiohttp-cors \
python-aiohttp-jinja2 \
python-aiohttp-session \
python-aiohttp-security \
python-requests-unixsocket2
## FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container
COPY "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn"

View File

@ -2,7 +2,7 @@
[![tests status](https://github.com/arcan1s/ahriman/actions/workflows/tests.yml/badge.svg)](https://github.com/arcan1s/ahriman/actions/workflows/tests.yml)
[![setup status](https://github.com/arcan1s/ahriman/actions/workflows/setup.yml/badge.svg)](https://github.com/arcan1s/ahriman/actions/workflows/setup.yml)
[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/arcan1s/ahriman?label=Docker%20image)](https://hub.docker.com/r/arcan1s/ahriman)
[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/arcan1s/ahriman?label=Docker%20image&sort=semver)](https://hub.docker.com/r/arcan1s/ahriman)
[![CodeFactor](https://www.codefactor.io/repository/github/arcan1s/ahriman/badge)](https://www.codefactor.io/repository/github/arcan1s/ahriman)
[![Documentation Status](https://readthedocs.org/projects/ahriman/badge/?version=latest)](https://ahriman.readthedocs.io)
@ -33,10 +33,12 @@ Every available option is described in the [documentation](https://ahriman.readt
The application provides reasonable defaults which allow to use it out-of-box; however additional steps (like configuring build toolchain and sudoers) are recommended and can be easily achieved by following install instructions.
## [FAQ](https://ahriman.readthedocs.io/en/stable/faq.html)
## [FAQ](https://ahriman.readthedocs.io/en/stable/faq/index.html)
## Live demos
* [Build status page](https://ahriman-demo.arcanis.me). You can log in as `demo` user by using `demo` password. However, you will not be able to run tasks. [HTTP API documentation](https://ahriman-demo.arcanis.me/api-docs) is also available.
* [Repository index](https://repo.arcanis.me/arcanisrepo/x86_64/).
* [Telegram feed](https://t.me/arcanisrepo).
Do you have any success story? You can [share it](https://github.com/arcan1s/ahriman/issues/new?template=04-discussion.md)!

View File

@ -8,9 +8,6 @@ cat <<EOF > "/etc/ahriman.ini.d/00-docker.ini"
[repository]
root = $AHRIMAN_REPOSITORY_ROOT
[settings]
database = $AHRIMAN_REPOSITORY_ROOT/ahriman.db
[web]
host = $AHRIMAN_HOST

View File

@ -6,7 +6,7 @@ for PACKAGE in "$@"; do
BUILD_DIR="$(mktemp -d)"
git clone https://aur.archlinux.org/"$PACKAGE".git "$BUILD_DIR"
cd "$BUILD_DIR"
makepkg --noconfirm --install --rmdeps --syncdeps
makepkg --nocheck --noconfirm --install --rmdeps --syncdeps
cd /
rm -r "$BUILD_DIR"
done

12051
docs/_static/architecture.svg vendored Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 1.4 MiB

721
docs/_static/logo.svg vendored Normal file
View File

@ -0,0 +1,721 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="800"
height="800"
version="1.1"
id="svg106"
sodipodi:docname="logo.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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="namedview106"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.8720703"
inkscape:cx="511.73292"
inkscape:cy="499.71414"
inkscape:window-width="3840"
inkscape:window-height="2160"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg106" />
<path
fill="#132b6d"
d="m 387.66175,2.9352426 c 109.978,-0.5206001 203.504,31.4880054 285.824,108.1504174 159.376,148.42203 165.076,403.05807 17.164,561.4021 -72.884,78.02402 -172.364,120.98802 -278.558,124.58202 -105.508,0.092 -196.612,-29.306 -277.44,-100.25401 C -17.844855,562.95974 -40.874855,327.5097 78.894545,164.89367 155.84375,60.416853 261.60375,10.958044 387.66175,2.9352426 Z"
id="path1"
style="stroke-width:2" />
<defs
id="defs2">
<linearGradient
id="gradient_0"
gradientUnits="userSpaceOnUse"
x1="361.42581"
y1="223.77209"
x2="195.62669"
y2="358.78311"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#C29024"
id="stop1" />
<stop
offset="1"
stop-color="#DCBB57"
id="stop2" />
</linearGradient>
</defs>
<path
fill="url(#gradient_0)"
d="M 351.39175,758.48578 C 168.77575,730.12777 41.748945,587.64375 38.358945,403.44571 34.725145,206.00568 197.09775,42.52665 394.25175,39.316449 c 199.908,-3.255 364.866,156.319231 367.572,354.681261 1.264,13.294 -0.766,28.52001 -2.266,41.84201 -22.772,202.34804 -192.312,343.02406 -397.788,324.19806 -2.656,-0.244 -8.104,-0.266 -10.378,-1.552 z"
id="path2"
style="fill:url(#gradient_0);stroke-width:2" />
<path
fill="#fade6b"
d="m 322.01375,466.26772 c -11.018,-19.004 -31.84,-33.106 -51.826,-41.634 -1.678,-0.714 -7.54,-2.124 -8.182,-3.564 l 0.732,-0.666 c 4,0.842 8.334,3.966 12.02,5.806 6.386,3.184 15.572,2.11 22.174,5.236 4.75,2.248 4.01,8.946 6.388,12.528 4.924,7.418 31.496,22.526 25.196,30.44801 -1.88,2.366 3.59,25.088 -6.502,27.406 9.19,-11.64 6.228,-23.022 0,-35.56001 z"
id="path3"
style="stroke-width:2" />
<path
fill="#f1ead8"
d="m 607.74175,596.82375 c 1.336,0.334 2.464,0.632 3.666,1.342 -20.054,9.052 -64.106,28.032 -86.62,22.686 4.1,-6.492 9.65,-12.676 16.658,-16.064 19.842,0.438 47.962,-0.334 66.296,-7.964 z"
id="path4"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 501.15175,566.49574 c 6.586,7.622 13.706,16.72001 22.154,22.30601 4.128,2.764 8.214,4.434 12.892,6.05 9.566,1.388 23.592,3.746 32.986,1.972 14.562,-1.188 28.228,-3.904 42.224,-8.022 l -1.062,3.132 c -0.626,1.91 -1.408,3.284 -2.604,4.89 -18.334,7.63 -46.454,8.402 -66.296,7.964 -7.008,3.388 -12.558,9.572 -16.658,16.064 -9.11,-5.624 -25.204,-20.256 -33.116,-27.858 -0.438,-2.818 -1.834,-5.878 -2.786,-8.594 3.066,-7.94801 11.252,-13.00801 12.266,-17.90401 z"
id="path5"
style="stroke-width:2" />
<path
fill="#f1ead8"
d="m 279.36575,419.47772 c 17.368,-2.17 52.85,13.874 66.39,23.914 16.654,12.346 42.944,41.42201 46.084,62.86401 l -0.632,0.818 c -7.4,-0.814 -14.928,-3.078 -22.004,0 -15.638,-34.97 -32.316,-54.81001 -66.512,-75.00601 -7.612,-4.496 -15.806,-7.926 -23.326,-12.59 z"
id="path6"
style="stroke-width:2" />
<path
fill="#f2e8a9"
d="m 358.50775,559.66374 c 12.018,13.204 20.532,31.28401 42.394,32.76001 26.828,1.808 75.452,-16.66001 100.25,-25.92801 -1.014,4.896 -9.2,9.956 -12.266,17.90401 0.952,2.716 2.348,5.776 2.786,8.594 -23.926,3.644 -42.772,14.97 -73.036,18.024 -31.48,3.176 -57.178,-20.208 -60.128,-51.35401 z"
id="path7"
style="stroke-width:2" />
<defs
id="defs8">
<linearGradient
id="gradient_1"
gradientUnits="userSpaceOnUse"
x1="251.38866"
y1="364.7413"
x2="250.98038"
y2="386.04666"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#8B5E10"
id="stop7" />
<stop
offset="1"
stop-color="#CF9A22"
id="stop8" />
</linearGradient>
</defs>
<path
fill="url(#gradient_1)"
d="m 310.19775,643.62576 c 2.576,-42.33201 43.824,-23.71801 68.946,-13.31801 29.856,12.36001 44.646,14.27401 76.866,17.40001 6.062,0.588 19.738,0.234 24.164,5.272 -4.906,4.506 -30.934,9.33 -37.886,8.6 -14.06,-1.944 -28.422,0.378 -42.516,0.02 -15.588,-0.394 -24.788,-3.174 -41.264,-0.02 -10.692,-0.35 -39.162,-6.928 -48.31,-12.01 l -0.164,-0.692 c -4.454,-4.498 -8.004,-10.198 -11.632,-15.38 h 1.106 c 3.348,3.464 6.672,7.448 10.69,10.128 z"
id="path8"
style="fill:url(#gradient_1);stroke-width:2" />
<path
fill="#e4c267"
d="m 533.18975,212.81168 3.008,1.8 c 104.752,81.45401 120.284,223.88804 39.258,327.17806 -4.874,6.214 -10.864,11.518 -15.55,17.874 -13.234,7.248 -22.01,22.26601 -36.562,27.66201 -3.272,-0.346 -14.796,-14.16001 -18.132,-17.28801 9.246,-9.45 22.016,-16.352 32.638,-26.984 75.99,-76.05602 84.014,-197.54404 14.068,-280.22005 -6.722,-7.946 -14.4,-14.688 -21.786,-21.97401 2.61,-8.98 1.014,-18.91 3.058,-28.048 z"
id="path9"
style="stroke-width:2" />
<defs
id="defs10">
<linearGradient
id="gradient_2"
gradientUnits="userSpaceOnUse"
x1="383.45288"
y1="318.2124"
x2="295.73892"
y2="203.79875"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#BF9029"
id="stop9" />
<stop
offset="1"
stop-color="#F5D354"
id="stop10" />
</linearGradient>
</defs>
<path
fill="url(#gradient_2)"
d="m 434.37375,137.51566 c 2.598,-0.164 5.328,-0.374 7.914,0 44.516,7.77801 92.47,33.43601 126.896,61.38602 7.438,7.668 16.4,14.876 22.864,23.372 2.62,2.794 5.176,5.692 8.21,8.044 5.566,3.826 22.78,23.15001 28.692,29.00401 l 0.008,0.522 c 0.052,5.284 2.926,14.418 2.624,16.914 1.07,8.98 6.816,17.276 9.974,25.644 32.534,86.22402 17.178,181.23004 -38.442,254.80205 -9.59,12.686 -20.71,25.49601 -33.178,35.41401 -3.856,3.068 -7.42,3.966 -0.752,4.206 -9.394,1.774 -23.42,-0.584 -32.986,-1.972 -4.678,-1.616 -8.764,-3.286 -12.892,-6.05 12.516,-9.682 25.068,-17.99401 36.6,-29.13801 4.686,-6.356 10.676,-11.66 15.55,-17.874 81.026,-103.29002 65.494,-245.72405 -39.258,-327.17806 l -3.008,-1.8 c -2.044,9.138 -0.448,19.068 -3.058,28.048 -20.19,-16.736 -57.964,-41.348 -84.916,-44.78 -4.862,6.39 -8.658,12.616 -14.43,18.532 -7.806,8.378 -15.312,17.27 -22.424,26.248 v -3.898 c -1.506,1.596 -4.512,4.54 -4.34,6.828 l 0.516,0.474 c -0.566,1.138 -1.052,2.3 -1.93,3.238 l -1.24,0.028 0.2,1.06001 c -4.05,-8.60801 1.232,-15.75801 3.436,-23.75601 26.818,-41.54401 24.194,-53.60601 -19.526,-73.22601 16.782,-3.452 30.824,-15.02601 48.896,-14.09201 z"
id="path10"
style="fill:url(#gradient_2);stroke-width:2" />
<path
fill="#e7aa1f"
d="m 592.04775,222.27368 c 2.62,2.794 5.176,5.692 8.21,8.044 8.066,13.52 19.78,29.05401 28.692,42.98401 -6.366,-3.072 -23.312,-30.26801 -30.038,-38.90201 -2.778,-3.566 -7.95,-7.296 -6.864,-12.126 z"
id="path11"
style="stroke-width:2" />
<path
fill="#051053"
d="m 600.25775,230.31768 c 5.566,3.826 22.78,23.15001 28.692,29.00401 l 0.008,0.522 c 0.052,5.284 2.926,14.418 2.624,16.914 -0.81,-1.204 -1.734,-2.318 -2.632,-3.456 -8.912,-13.93 -20.626,-29.46401 -28.692,-42.98401 z"
id="path12"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 536.19775,214.61168 c -9.436,-16.308 -80.554,-44.98201 -95.5,-43.60601 -2.88,-2.338 -5.638,-6.154 -7.546,-9.334 13.846,-0.878 61.092,18.238 74.408,25.094 7.224,3.72 43.202,27.84801 43.214,27.84601 3.21,2.37 5.956,5.258 9.132,7.662 4.042,5.416 9.626,9.648 14.302,14.496 93.102,96.54202 79.466,249.74005 -15.778,339.83206 -3.328,3.14801 -18.614,17.85401 -22.232,18.25001 -4.678,-1.616 -8.764,-3.286 -12.892,-6.05 12.516,-9.682 25.068,-17.99401 36.6,-29.13801 4.686,-6.356 10.676,-11.66 15.55,-17.874 81.026,-103.29002 65.494,-245.72405 -39.258,-327.17806 z"
id="path13"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 434.37375,137.51566 c 2.598,-0.164 5.328,-0.374 7.914,0 44.516,7.77801 92.47,33.43601 126.896,61.38602 2.568,7.928 14.072,10.708 15.774,18.372 l -0.474,0.94 -2.092,0.246 c -0.048,0.186 -10.608,12.996 -11.95,12.526 -3.166,-1.106 -7.656,-9.138 -10.536,-8.712 -3.176,-2.404 -5.922,-5.292 -9.132,-7.662 -0.012,0.002 -35.99,-24.12601 -43.214,-27.84601 -13.316,-6.856 -60.562,-25.972 -74.408,-25.094 1.908,3.18 4.666,6.996 7.546,9.334 14.946,-1.376 86.064,27.29801 95.5,43.60601 l -3.008,-1.8 c -2.044,9.138 -0.448,19.068 -3.058,28.048 -20.19,-16.736 -57.964,-41.348 -84.916,-44.78 -4.862,6.39 -8.658,12.616 -14.43,18.532 -7.806,8.378 -15.312,17.27 -22.424,26.248 v -3.898 c -1.506,1.596 -4.512,4.54 -4.34,6.828 l 0.516,0.474 c -0.566,1.138 -1.052,2.3 -1.93,3.238 l -1.24,0.028 0.2,1.06001 c -4.05,-8.60801 1.232,-15.75801 3.436,-23.75601 26.818,-41.54401 24.194,-53.60601 -19.526,-73.22601 16.782,-3.452 30.824,-15.02601 48.896,-14.09201 z"
id="path14"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 412.09175,152.87167 c 12.74,-3.468 25.54,-4.784 38.71,-3.946 -6.848,2.32 -14.484,5.572 -20.016,10.326 8.062,3.682 21.354,5.528 30.612,8.39 19.908,6.152 75.712,30.48001 89.376,46.97001 -0.012,0.002 -35.99,-24.12601 -43.214,-27.84601 -13.316,-6.856 -60.562,-25.972 -74.408,-25.094 1.908,3.18 4.666,6.996 7.546,9.334 14.946,-1.376 86.064,27.29801 95.5,43.60601 l -3.008,-1.8 c -17.866,-18.572 -65.548,-36.19801 -90.902,-40.93001 3.608,7.782 6.348,15.752 2.928,24.19801 -4.862,6.39 -8.658,12.616 -14.43,18.532 -7.806,8.378 -15.312,17.27 -22.424,26.248 v -3.898 c 22.078,-32.98 57.308,-46.31801 3.73,-84.09001 z"
id="path15"
style="stroke-width:2" />
<path
fill="#f1ead8"
d="m 442.28775,171.88167 c 25.354,4.732 73.036,22.35801 90.902,40.93001 -2.044,9.138 -0.448,19.068 -3.058,28.048 -20.19,-16.736 -57.964,-41.348 -84.916,-44.78 3.42,-8.44601 0.68,-16.41601 -2.928,-24.19801 z"
id="path16"
style="stroke-width:2" />
<defs
id="defs17">
<linearGradient
id="gradient_3"
gradientUnits="userSpaceOnUse"
x1="259.85068"
y1="248.27858"
x2="350.85385"
y2="408.95212"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#061757"
id="stop16" />
<stop
offset="1"
stop-color="#1C4897"
id="stop17" />
</linearGradient>
</defs>
<path
fill="url(#gradient_3)"
d="m 628.94975,259.32169 c 35.888,36.25 71.52,72.79001 107.964,108.48002 6.736,6.598 18.816,21.616 24.91,26.196 1.264,13.294 -0.766,28.52001 -2.266,41.84201 -22.772,202.34804 -192.312,343.02406 -397.788,324.19806 -2.656,-0.244 -8.104,-0.266 -10.378,-1.552 -4.572,-6.652 -23.912,-22.76601 -31.626,-30.48801 l -117.162,-117.50802 c -11.006,-10.966 -46.288,-42.43401 -53.304,-54.48401 -4.57,-5.32 -10.27,-9.648 -14.854,-15.058 4.872,0.144 18.938,7.52 23.586,10.336 6.858,1.708 20.052,4.126 26.25,6.798 0.434,-1.258 0.146,-2.694 0,-3.998 0.138,-1.692 0.09,-3.306 0,-5 3.348,0.634 6.652,2.408 10.05,2.2 13.202,5.656 24.534,12.708 34.05,23.62 3.788,3.09 7.482,6.23801 11.126,9.49601 4.716,4.008 9.52,7.936 13.794,12.424 1.884,0.704 5.45,2.046 6.762,3.614 1.584,0.97 3.154,2.014 4.78,2.904 7.256,3.166 14.768,8.762 21.092,13.49 1.516,2.334 3.288,4.486 5.016,6.664 l 7.45,10.00201 c 3.628,5.182 7.178,10.882 11.632,15.38 l 0.164,0.692 c 9.148,5.082 37.618,11.66 48.31,12.01 16.476,-3.154 25.676,-0.374 41.264,0.02 14.094,0.358 28.456,-1.964 42.516,-0.02 6.952,0.73 32.98,-4.094 37.886,-8.6 7.398,7.31 18.44,8.658 28.374,7.392 40.55,-5.168 97.53,-34.27201 123.034,-67.37801 -2.714,-0.424 9.054,-10.22 9.25,-12.97 -7.204,1.354 -10.72,9.924 -18.264,10.996 -3.768,2.22 -7.816,4.312 -11.16,7.146 -1.202,-0.71 -2.33,-1.008 -3.666,-1.342 1.196,-1.606 1.978,-2.98 2.604,-4.89 l 1.062,-3.132 c -13.996,4.118 -27.662,6.834 -42.224,8.022 -6.668,-0.24 -3.104,-1.138 0.752,-4.206 12.468,-9.918 23.588,-22.72801 33.178,-35.41401 55.62,-73.57201 70.976,-168.57803 38.442,-254.80205 -3.158,-8.368 -8.904,-16.664 -9.974,-25.644 0.302,-2.496 -2.572,-11.63 -2.624,-16.914 z"
id="path17"
style="fill:url(#gradient_3);stroke-width:2" />
<path
fill="#fade6b"
d="m 637.21175,576.96974 c 4.14,-2.36 8.288,-4.69 12.494,-6.932 -5.274,7.16 -11.4,17.29401 -18.124,22.95601 -2.714,-0.424 9.054,-10.22 9.25,-12.97 -7.204,1.354 -10.72,9.924 -18.264,10.996 3.782,-3.136 14.3,-8.644 15.882,-12.846 z"
id="path18"
style="stroke-width:2" />
<path
fill="#f2e8a9"
d="m 637.21175,576.96974 1.238,1.20401 c -1.582,4.202 -12.1,9.71 -15.882,12.846 -3.768,2.22 -7.816,4.312 -11.16,7.146 -1.202,-0.71 -2.33,-1.008 -3.666,-1.342 1.196,-1.606 1.978,-2.98 2.604,-4.89 l 1.062,-3.132 c 9.172,-3.09 17.482,-6.914 25.804,-11.83201 z"
id="path19"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 358.50775,661.57976 c 16.476,-3.154 25.676,-0.374 41.264,0.02 14.094,0.358 28.456,-1.964 42.516,-0.02 -25.31,6.146 -58.224,4.784 -83.78,0 z"
id="path20"
style="stroke-width:2" />
<defs
id="defs21">
<linearGradient
id="gradient_4"
gradientUnits="userSpaceOnUse"
x1="178.9133"
y1="342.13019"
x2="155.9601"
y2="362.37878"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#CC991E"
id="stop20" />
<stop
offset="1"
stop-color="#F2B831"
id="stop21" />
</linearGradient>
</defs>
<path
fill="url(#gradient_4)"
d="m 134.44575,540.94774 c 4.872,0.144 18.938,7.52 23.586,10.336 6.858,1.708 20.052,4.126 26.25,6.798 0.434,-1.258 0.146,-2.694 0,-3.998 0.138,-1.692 0.09,-3.306 0,-5 3.348,0.634 6.652,2.408 10.05,2.2 13.202,5.656 24.534,12.708 34.05,23.62 3.788,3.09 7.482,6.23801 11.126,9.49601 4.716,4.008 9.52,7.936 13.794,12.424 1.884,0.704 5.45,2.046 6.762,3.614 1.584,0.97 3.154,2.014 4.78,2.904 7.256,3.166 14.768,8.762 21.092,13.49 1.516,2.334 3.288,4.486 5.016,6.664 l 7.45,10.00201 c 3.628,5.182 7.178,10.882 11.632,15.38 l 0.164,0.692 c -22.282,-4.896 -55.696,-23.88201 -74.236,-37.44601 -6.744,-4.934 -12.552,-11.388 -19.652,-15.766 -6.676,-4.12 -15.06,-5.966 -22.186,-9.388 -16.632,-7.988 -30.922,-18.98801 -44.824,-30.96401 -4.57,-5.32 -10.27,-9.648 -14.854,-15.058 z"
id="path21"
style="fill:url(#gradient_4);stroke-width:2" />
<path
fill="#d6991c"
d="m 158.03175,551.28374 c 6.858,1.708 20.052,4.126 26.25,6.798 1.448,0.596 2.168,1.102 2.948,2.48 l -0.558,0.666 c -3.77,-0.136 -27.166,-8.046 -28.64,-9.944 z"
id="path22"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 242.85175,607.32775 c 7.25,0.168 31.11,8.666 40.444,11.75 -14.638,0.038 -27.2,-6.238 -40.444,-11.75 z"
id="path23"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 232.69375,596.82375 c 6.662,0.62 22.044,5.462 27.37,3.614 1.584,0.97 3.154,2.014 4.78,2.904 -4.194,1.55 -18.89,-0.318 -26.814,1.446 z"
id="path24"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 209.78375,574.90374 c -2.394,-0.948 -7.676,-3.032 -7.456,-6.196 5.142,-1.48 19.682,5.378 26.054,6.196 3.788,3.09 7.482,6.23801 11.126,9.49601 l -0.16,0.142 c -3.374,0.606 -25.568,-7.70801 -29.564,-9.63801 z"
id="path25"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 209.78375,574.90374 c 3.996,1.93 26.19,10.24401 29.564,9.63801 l 0.16,-0.142 c 4.716,4.008 9.52,7.936 13.794,12.424 1.884,0.704 5.45,2.046 6.762,3.614 -5.326,1.848 -20.708,-2.994 -27.37,-3.614 -10.77,-1.75 -16.314,-4.876 -19.558,-16.004 -1.528,-1.78 -2.85,-3.59801 -3.352,-5.91601 z"
id="path26"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 209.78375,574.90374 c 3.996,1.93 26.19,10.24401 29.564,9.63801 l 0.16,-0.142 c 4.716,4.008 9.52,7.936 13.794,12.424 v 0 c -11.244,-0.884 -22.286,-6.858 -31.866,-12.424 -2.804,-0.374 -5.434,-2.774 -8.3,-3.58 -1.528,-1.78 -2.85,-3.59801 -3.352,-5.91601 z"
id="path27"
style="stroke-width:2" />
<path
fill="#ad7214"
d="m 221.43575,584.39975 c 6.578,-0.56 30.096,8.298 31.866,12.424 -11.244,-0.884 -22.286,-6.858 -31.866,-12.424 z"
id="path28"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 266.41175,531.65974 c -4.998,-0.03 -11.098,-9.27801 -14.01,-12.81601 -78.2,-95.08401 -44.296,-239.09604 68.622,-289.88605 14.626,-6.58 87.39,-28.004 83.98,-12.018 0.29,5.32 -5.89,12.826 -5.742,19.654 l 0.8,-0.356 0.256,-0.984 c 0.838,-3.116 3.132,-7.658 4.686,-10.42 v 0 c -2.204,7.998 -7.486,15.148 -3.436,23.75601 l -0.2,-1.06001 1.24,-0.028 c 0.878,-0.938 1.364,-2.1 1.93,-3.238 l -0.516,-0.474 c -0.172,-2.288 2.834,-5.232 4.34,-6.828 v 3.898 c 7.112,-8.978 14.618,-17.87 22.424,-26.248 l 0.5,0.152 c 8.212,2.444 16.47,3.944 24.602,6.854 58.574,20.972 106.85,72.05001 120.456,133.45202 1.73,7.81001 2.632,15.79601 4.472,23.57201 0.174,4.016 1.316,11.12 -0.142,14.692 l -1.322,0.664 1.154,0.176 c 1.286,3.432 0.364,9.786 0.31,13.526 0.428,4.816 0.606,10.62001 0,15.40801 -1.662,4.574 -2.66,9.378 -3.582,14.148 -0.862,5.382 -1.694,10.842 -3.742,15.924 -1.502,3.656 -3.308,7.462 -4.308,11.294 -0.442,4.27201 -3.664,10.89601 -6.116,14.42401 -2.28,4.28 -4.82,10.524 -8.172,14.028 -2.766,4.198 -5.424,8.452 -8.062,12.73 l -10.636,13.256 c -0.812,1.354 -10.158,11.70601 -11.41,12.74801 -4.732,2.976 -7.86,5.02 -11.552,9.288 -4.794,2.344 -9.02,6.04 -13.816,8.136 -4.916,2.576 -9.95,5.226 -14.068,8.998 -5.336,1.804 -10.23,3.636 -15.1,6.486 -3,0.812 -11.478,3.87 -14.124,3.644 -5.37,1.882 -11.066,2.43 -16.396,4.486 l -14.888,2.206 c -3.228,-0.058 -14.524,1.172 -16.482,0 -2.668,0.884 -14.2,-1.2 -17.154,-2.206 -4.388,-1.97 -13.234,-3.4 -15.17,-4.486 -15.284,-4 -26.706,-61.61201 4.84,-58.55001 5.12,0.178 10.212,1.104 15.266,1.896 -0.322,-4.59 -1.47,-8.966 -2.758,-13.362 -31.792,-69.38401 -101.182,-95.30202 -174.692,-84.31001 28.904,2.816 52.742,14.29 77.006,28.634 14.684,13.388 42.828,39.46001 22.146,59.30801 -4.42,-5.66 -9.796,-10.928 -13.456,-17.124 l -1.134,0.23 0.924,-0.544 0.246,0.612 -1.168,-0.966 c -0.378,1.04 0.1,2.79 0.238,3.908 -0.494,8.656 -0.63,17.812 -1.922,26.378 -0.986,1.08 -1.914,2.264 -3.172,3.032 -4.348,3.636 -8.422,7.43801 -12.466,11.40401 -1.992,-3.07 -5.034,-6.59401 -6.57,-9.84601 -2.598,-1.562 -2.622,-4.334 -3.65,-6.816 l -0.892,0.308 c -0.248,2.022 1.28,3.668 1.268,5.77 l -0.744,0.738 c 2.36,3.862 7.746,10.52601 7.948,15.01601 -5.642,-0.656 -11.25,-1.548 -16.884,-2.268 z"
id="path29"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 271.23775,505.65573 4.11,2.688 c 0.612,3.864 2.48,7.024 4.018,10.568 -2.598,-1.562 -2.622,-4.334 -3.65,-6.816 l -0.892,0.308 c -0.248,2.022 1.28,3.668 1.268,5.77 l -0.744,0.738 c -1.114,-4.514 -3.114,-8.68 -4.11,-13.256 z"
id="path30"
style="stroke-width:2" />
<path
fill="#051053"
d="m 397.67375,507.07373 c 2.356,4.01 4.79,7.942 7.33,11.838 -3.3,-1.106 -7.652,-4.4 -10.786,-4.59 l 1.848,-0.566 c 1.032,-1.614 0.804,-4.254 1.44,-6.188 z"
id="path31"
style="stroke-width:2" />
<path
fill="#0f0e1a"
d="m 393.38575,498.19573 c 3.194,2.542 2.828,5.462 4.288,8.878 l -0.168,0.494 c -0.636,1.934 -0.408,4.574 -1.44,6.188 l -1.848,0.566 c -4.74,-0.682 -9.642,-1.346 -13.34,-4.66 5.12,0.178 10.212,1.104 15.266,1.896 -0.322,-4.59 -1.47,-8.966 -2.758,-13.362 z"
id="path32"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 405.00375,216.93968 c 0.29,5.32 -5.89,12.826 -5.742,19.654 l 0.8,-0.356 0.256,-0.984 c 0.838,-3.116 3.132,-7.658 4.686,-10.42 v 0 c -2.204,7.998 -7.486,15.148 -3.436,23.75601 l -0.2,-1.06001 1.24,-0.028 c 0.878,-0.938 1.364,-2.1 1.93,-3.238 l -0.516,-0.474 c -0.172,-2.288 2.834,-5.232 4.34,-6.828 v 3.898 c -5.74,7.47601 -10.278,15.97801 -14.976,24.13401 2.614,-16.47 4.536,-32.74201 11.618,-48.05401 z"
id="path33"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 376.03775,568.21174 c 3.14,-7.134 6.892,-14.264 9.44,-21.616 2.51,8.576 3.87,17.374 5.73,26.102 -4.388,-1.97 -13.234,-3.4 -15.17,-4.486 z"
id="path34"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 275.34775,508.34373 c 7.554,3.424 15.174,6.414 23.054,9.01 -4.348,3.636 -8.422,7.43801 -12.466,11.40401 -1.992,-3.07 -5.034,-6.59401 -6.57,-9.84601 -1.538,-3.544 -3.406,-6.704 -4.018,-10.568 z"
id="path35"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 580.81575,378.64171 c 0.174,4.016 1.316,11.12 -0.142,14.692 l -1.322,0.664 c -8.51,-1.606 -16.614,-3.178 -25.25,-4.102 8.398,-6.016 16.886,-8.52 26.714,-11.254 z"
id="path36"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 554.10175,411.69971 c 8.586,-2.24 17.924,-2.716 26.714,-4 0.428,4.816 0.606,10.62001 0,15.40801 -8.872,-2.66 -19.79,-5.044 -26.714,-11.40801 z"
id="path37"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 413.80575,549.08374 c 5.198,7.878 7.314,17.22 11.038,25.82 -3.228,-0.058 -14.524,1.172 -16.482,0 1.018,-8.646 2.216,-17.686 5.444,-25.82 z"
id="path38"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 526.91575,484.43773 c 9.316,1.67 19.154,5.096 27.98,8.488 -2.766,4.198 -5.424,8.452 -8.062,12.73 -7.26,-6.506 -15.232,-12.516 -19.918,-21.218 z"
id="path39"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 549.10575,437.25572 c 9.318,-0.64 18.79,-0.084 28.128,0 -0.862,5.382 -1.694,10.842 -3.742,15.924 -8.43,-5.086 -16.78,-9.56 -24.386,-15.924 z"
id="path40"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 439.73175,543.29174 1.36,1.452 c 6.326,6.73 9.89,15.802 15.036,23.468 -5.37,1.882 -11.066,2.43 -16.396,4.486 z"
id="path41"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 539.67175,462.21972 c 9.972,-0.004 19.626,1.052 29.512,2.254 -0.442,4.27201 -3.664,10.89601 -6.116,14.42401 -8.166,-3.222 -17.172,-10.556 -23.396,-16.67801 z"
id="path42"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 488.88575,521.69573 c 7.732,3.84201 19.168,12.47201 24.35,19.25201 -4.794,2.344 -9.02,6.04 -13.816,8.136 -4.688,-8.85 -7.936,-17.748 -10.534,-27.38801 z"
id="path43"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 509.94175,505.65573 c 5.494,1.07 8.69,2.82 13.364,5.902 5.104,1.702 8.644,4.112 12.892,7.354 -0.812,1.354 -10.158,11.70601 -11.41,12.74801 -2.844,-4.58 -6.188,-9.33401 -8.274,-14.30601 -2.536,-3.532 -4.474,-7.872 -6.572,-11.698 z"
id="path44"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 465.35375,533.92774 c 7.502,6.24 15.294,15.644 19.998,24.154 -5.336,1.804 -10.23,3.636 -15.1,6.486 -3.214,-9.588 -4.238,-20.568 -4.898,-30.64 z"
id="path45"
style="stroke-width:2" />
<path
fill="#2356ae"
d="M 351.39175,758.48578 C 168.77575,730.12777 41.748945,587.64375 38.358945,403.44571 34.725145,206.00568 197.09775,42.52665 394.25175,39.316449 c 199.908,-3.255 364.866,156.319231 367.572,354.681261 -6.094,-4.58 -18.174,-19.598 -24.91,-26.196 -36.444,-35.69001 -72.076,-72.23002 -107.964,-108.48002 -5.912,-5.854 -23.126,-25.17801 -28.692,-29.00401 -3.034,-2.352 -5.59,-5.25 -8.21,-8.044 -6.464,-8.496 -15.426,-15.704 -22.864,-23.372 -34.426,-27.95001 -82.38,-53.60801 -126.896,-61.38602 -2.586,-0.374 -5.316,-0.164 -7.914,0 -18.072,-0.934 -32.114,10.64001 -48.896,14.09201 43.72,19.62 46.344,31.682 19.526,73.22601 v 0 c -1.554,2.762 -3.848,7.304 -4.686,10.42 l -0.256,0.984 -0.8,0.356 c -0.148,-6.828 6.032,-14.334 5.742,-19.654 3.41,-15.986 -69.354,5.438 -83.98,12.018 -112.918,50.79001 -146.822,194.80204 -68.622,289.88605 2.912,3.538 9.012,12.78601 14.01,12.81601 5.634,0.72 11.242,1.612 16.884,2.268 -0.202,-4.49 -5.588,-11.15401 -7.948,-15.01601 l 0.744,-0.738 c 0.012,-2.102 -1.516,-3.748 -1.268,-5.77 l 0.892,-0.308 c 1.028,2.482 1.052,5.254 3.65,6.816 1.536,3.252 4.578,6.77601 6.57,9.84601 4.044,-3.966 8.118,-7.76801 12.466,-11.40401 1.258,-0.768 2.186,-1.952 3.172,-3.032 1.292,-8.566 1.428,-17.722 1.922,-26.378 -0.138,-1.118 -0.616,-2.868 -0.238,-3.908 l 1.168,0.966 -0.246,-0.612 -0.924,0.544 1.134,-0.23 c 3.66,6.196 9.036,11.464 13.456,17.124 20.682,-19.848 -7.462,-45.92001 -22.146,-59.30801 8.322,2.714 22.978,21.546 26.672,29.42201 2.368,5.048 2.81,14.832 4.236,17.488 3.938,-9.238 -6.242,-21.60201 -4.594,-23.16201 6.228,12.53801 9.19,23.92001 0,35.56001 -11.034,9.136 -29.284,21.156 -36.122,33.99601 -15.95,29.946 -3.004,58.48801 7.948,85.92401 1.766,3.338 5.028,8.098 5.668,11.75001 h -1.106 l -7.45,-10.00201 c -1.728,-2.178 -3.5,-4.33 -5.016,-6.664 -6.324,-4.728 -13.836,-10.324 -21.092,-13.49 -1.626,-0.89 -3.196,-1.934 -4.78,-2.904 -1.312,-1.568 -4.878,-2.91 -6.762,-3.614 -4.274,-4.488 -9.078,-8.416 -13.794,-12.424 -3.644,-3.258 -7.338,-6.40601 -11.126,-9.49601 -9.516,-10.912 -20.848,-17.964 -34.05,-23.62 -3.398,0.208 -6.702,-1.566 -10.05,-2.2 0.09,1.694 0.138,3.308 0,5 0.146,1.304 0.434,2.74 0,3.998 -6.198,-2.672 -19.392,-5.09 -26.25,-6.798 -4.648,-2.816 -18.714,-10.192 -23.586,-10.336 4.584,5.41 10.284,9.738 14.854,15.058 7.016,12.05 42.298,43.51801 53.304,54.48401 l 117.162,117.50802 c 7.714,7.722 27.054,23.83601 31.626,30.48801 z"
id="path46"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 179.65375,204.78568 0.312,-1.174 0.54,0.326 c 1.66,8.908 0.01,23.462 3.776,31.23 -0.946,2.464 -0.94,5.09 -2.088,7.614 -0.896,-7.214 -1.61,-14.446 -2.54,-21.656 -0.13,-5.46 -0.212,-10.878 0,-16.34 z"
id="path47"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 125.81775,276.75769 c 2.17,11.74 9.116,22.444 12.934,33.79201 l -0.57,0.518 c -1.16,-3.654 -7.662,-20.46601 -9.84,-22.36001 l -0.976,0.068 c -1.38,1.692 -2.846,2.256 -4.866,3.024 -2.616,6.924 -1.898,24.47801 -3.168,33.15201 -0.472,-15.43 -0.356,-34.15801 6.486,-48.19401 z"
id="path48"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 274.23575,141.76967 c -2.074,7.182 -3.328,13.142 -2.998,20.634 -4.176,2.324 -7.592,4.762 -11.174,7.91 v -2.354 c 1.878,-6.262 2.766,-12.768 4.78,-19.034 3.524,-1.72 6.27,-4.824 9.392,-7.156 z"
id="path49"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 371.74975,108.36966 c -3.86,7.4 -7.354,14.524 -9.404,22.688 v 0 c -3.648,0.82 -7.228,1.122 -10.954,1.38 4.392,-6.38 5.642,-13.5 10.954,-19.87 l 1.312,1.376 c 2.71,-0.242 5.8,-4.024 8.092,-5.574 z"
id="path50"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 268.33575,131.05766 c -1.042,5.972 -2.31,11.92001 -3.492,17.86801 -2.014,6.266 -2.902,12.772 -4.78,19.034 -1.326,-4.864 3.318,-9.734 1.244,-14.208 -22.57,-10.084 -17.62,14.712 -26.708,18.13 6.172,-15.816 20.434,-30.548 33.736,-40.82401 z"
id="path51"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 179.65375,196.07968 c -0.244,2.936 -0.14,5.77 0,8.706 -0.212,5.462 -0.13,10.88 0,16.34 -2.87,1.676 -3.574,6.084 -4.174,9.192 -1.636,3.874 -3.642,7.834 -4.67,11.914 l -0.244,0.106 0.41,-0.728 -0.192,-0.106 c 2.75,-11.394 5.076,-8.03 -4.17,-11.186 -1.178,2.228 -4.1,9.672 -5.944,10.542 4.934,-15.602 12.448,-29.868 18.984,-44.78 z"
id="path52"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 456.12775,109.52166 c 3.564,1.658 10.414,-0.138 14.124,-1.152 -9.878,8.046 -21.92,17.846 -27.964,29.146 -2.586,-0.374 -5.316,-0.164 -7.914,0 l -6.334,-3.096 c 7.916,-6.85 14.976,-14.806 22.762,-21.852 1.752,-1.066 3.52,-2.074 5.326,-3.046 z"
id="path53"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 100.50375,364.60771 c 8.122,7.8 22.772,25.956 30.762,31.252 0.936,5.038 2.374,10.71 2.462,15.774 -12.286,-9.396 -17.796,-19.394 -28.126,-27.642 0.096,1.026 0.082,1.858 -0.212,2.84 -2.522,-7.432 -3.886,-14.462 -4.886,-22.224 z"
id="path54"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 96.515745,442.51972 c 8.566005,4.34 36.750005,23.486 42.236005,30.46001 l 0.276,0.808 c 6.398,2.844 8.096,8.69 8.058,15.766 l -0.588,-0.544 c -1.434,-1.32 -10.678,-7.62 -12.052,-7.594 -5.946,-3.566 -23.722,-21.69601 -29.056,-20.70801 -3.03,-6.03 -5.978005,-12.092 -8.874005,-18.188 z"
id="path55"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 121.77975,525.87374 c 19.42,6.36 38.498,14.12 57.874,20.722 l 0.548,0.758 1.826,-0.056 c 1.258,1.488 1.388,4.868 2.254,6.786 0.146,1.304 0.434,2.74 0,3.998 -6.198,-2.672 -19.392,-5.09 -26.25,-6.798 -4.648,-2.816 -18.714,-10.192 -23.586,-10.336 -4.45,-4.812 -8.812,-9.764 -12.666,-15.074 z"
id="path56"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 271.23775,162.40367 c 7.99,-6.254 18.884,-10.416 28.25,-14.234 16.76,-6.832 13.44,-7.376 25.658,-19.48401 10.768,-10.672 29.362,-23.208 44.058,-28.062 -2.508,3.886 -5.042,7.672 -6.858,11.944 -5.312,6.37 -6.562,13.49 -10.954,19.87 -0.974,1.678 -1.832,2.932 -3.262,4.254 l -0.532,-0.056 c 0.956,-3.102 4.54,-2.84 3.518,-6.662 l -2.128,-2.174 c -8.514,3.742 -77.504,34.61201 -77.75,34.60401 z"
id="path57"
style="stroke-width:2" />
<defs
id="defs58">
<linearGradient
id="gradient_5"
gradientUnits="userSpaceOnUse"
x1="145.13785"
y1="328.17804"
x2="117.22018"
y2="280.89636"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#D79A18"
id="stop57" />
<stop
offset="1"
stop-color="#F6C842"
id="stop58" />
</linearGradient>
</defs>
<path
fill="url(#gradient_5)"
d="m 105.38975,460.70772 c 5.334,-0.988 23.11,17.14201 29.056,20.70801 4.286,3.456 9.396,6.13 13.392,9.86 0.278,-2.39 0.424,-4.632 1.462,-6.838 l 0.504,-0.106 c 0.058,-0.954 -0.086,-7.128 0.79,-5.038 1.712,4.084 3.956,1.936 4.492,8.664 l 0.486,-0.014 c 2.38,7.206 8.172,8.99 13.068,13.884 l -0.348,0.398 c 2.612,0.138 4.874,0.24 7.188,1.558 0.816,0.698 1.66,1.344 2.532,1.97 l 0.462,1.048 c -1.04,0.308 -0.606,0.28 -1.274,0.272 3.704,0.932 3.808,4.058 4.994,7.248 v 0 c 2.772,3.696 5.17,7.268 6.946,11.55201 -1.732,-0.248 -24.262,-10.67601 -16.892,-1.472 2.482,3.098 5.226,7.084 8.34,9.526 2.636,1.906 4.292,5.756 7.29,7.02 h 1.262 l -1.262,2.344 c 0.818,1.872 1.938,2.472 3.716,3.304 l -0.66,0.048 c -2.968,0.184 -9.982,-2.572 -6.652,2.44 0.09,1.694 0.138,3.308 0,5 -0.866,-1.918 -0.996,-5.298 -2.254,-6.786 l -1.826,0.056 -0.548,-0.758 c -0.52,-3.778 -6.05,-8.072 -8.808,-10.5 -24.584,-13.75401 -54.27,-50.32801 -65.456,-75.38802 z"
id="path58"
style="fill:url(#gradient_5);stroke-width:2" />
<path
fill="#f1be39"
d="m 170.84575,536.09574 c 0.178,0.002 16.806,6.982 17.032,7.196 0.818,1.872 1.938,2.472 3.716,3.304 l -0.66,0.048 c -2.968,0.184 -9.982,-2.572 -6.652,2.44 0.09,1.694 0.138,3.308 0,5 -0.866,-1.918 -0.996,-5.298 -2.254,-6.786 l -1.826,0.056 -0.548,-0.758 c -0.52,-3.778 -6.05,-8.072 -8.808,-10.5 z"
id="path59"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 182.19375,514.32173 c -5.22,-0.312 -16.074,-7.81 -20,-10.892 -0.398,-0.312 -4.628,-3.938 -2.568,-3.994 4.124,-0.114 11.04,6.52 14.26,8.908 0.87,-0.988 2.086,-1.036 3.314,-1.27 3.704,0.932 3.808,4.058 4.994,7.248 z"
id="path60"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 177.19975,507.07373 c 3.704,0.932 3.808,4.058 4.994,7.248 -2.664,-2.118 -5.5,-4.052 -8.308,-5.978 0.87,-0.988 2.086,-1.036 3.314,-1.27 z"
id="path61"
style="stroke-width:2" />
<defs
id="defs62">
<linearGradient
id="gradient_6"
gradientUnits="userSpaceOnUse"
x1="238.76126"
y1="143.77654"
x2="270.52316"
y2="95.432106"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#FAD84F"
id="stop61" />
<stop
offset="1"
stop-color="#FFF5A9"
id="stop62" />
</linearGradient>
</defs>
<path
fill="url(#gradient_6)"
d="m 362.34575,131.05766 c 26.81,-3.184 19.722,-1.768 42.234,-13.04 19.684,-9.856 41.194,-16.094 63.324,-15.652 -4.056,2.182 -8.086,4.39 -11.776,7.156 -1.806,0.972 -3.574,1.98 -5.326,3.046 -7.786,7.046 -14.846,15.002 -22.762,21.852 l 6.334,3.096 c -18.072,-0.934 -32.114,10.64001 -48.896,14.09201 -3.1,0.442 -6.45,0.35 -9.44,1.264 -3.958,1.83 -9.35,-0.016 -13.526,1.328 l -0.166,0.49 c 4.412,1.276 9.87,1.98 13.692,4.562 -11.014,0.822 -21.384,-2.856 -32.396,-2.412 -0.74,-0.772 -5.22,0.294 -7.562,-0.282 l 0.286,-0.044 c -8.446,-2.598 -0.096,-4.918 2.406,-7.588 6.796,-3.554 22.95,-8.952 23.574,-17.86801 z"
id="path62"
style="fill:url(#gradient_6);stroke-width:2" />
<path
fill="#e4c267"
d="m 341.76375,151.60767 c 11.034,-5.176 26.9,-6.422 39.114,-7.498 -2.7,3.496 -6.968,3.658 -4.84,8.762 -3.958,1.83 -9.35,-0.016 -13.526,1.328 l -0.166,0.49 c -4.888,-1.222 -8.504,-1.066 -13.358,0 -2.746,0.4 -8.482,-0.994 -10.622,-2.552 l 0.184,-0.502 -0.088,0.422 0.506,-0.548 z"
id="path63"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 424.84375,132.43766 c 9.142,-6.23 14.826,-16.674 25.958,-19.87 -7.786,7.046 -14.846,15.002 -22.762,21.852 l 6.334,3.096 c -18.072,-0.934 -32.114,10.64001 -48.896,14.09201 -3.1,0.442 -6.45,0.35 -9.44,1.264 -2.128,-5.104 2.14,-5.266 4.84,-8.762 8.736,-2.842 14.512,-8.95201 24.126,-9.69001 2.98,-2.124 16.504,-3.504 19.84,-1.982 z"
id="path64"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 405.00375,134.41966 c 2.98,-2.124 16.504,-3.504 19.84,-1.982 -3.412,3.298 -15.364,2.648 -19.84,1.982 z"
id="path65"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 348.98775,127.79966 2.128,2.174 c 1.022,3.822 -2.562,3.56 -3.518,6.662 l 0.532,0.056 c 1.43,-1.322 2.288,-2.576 3.262,-4.254 3.726,-0.258 7.306,-0.56 10.954,-1.38 -0.624,8.91601 -16.778,14.31401 -23.574,17.86801 -7.41,2.68 -9.978,8.094 -16.164,11.038 -3.652,1.74 -27.878,3.596 -21.164,11.206 l -1.672,0.284 6.764,0.428 c -13.404,2.41 -17.64,4.718 -29.284,7.922 6.38,1.602 10.798,-2.57 18.448,0.768 h 2.702 l -0.042,1.276 c -7.05,4.88 -18.516,5.498 -27.53,13.56001 -1.344,1.2 -2.83,2.678 -4.418,3.494 -4.23,1.326 -8.724,2.754 -13.11,3.378 -1.89,1.25 -12.68,4.234 -15.272,4.588 v 0 -2.082 l -2.28,-3.718 c -4.61,0.068 -7.042,12.34 -7.368,15.872 -8.018,0.742 -11.65,9.846 -16.818,14.858 -3.88,-1.22 -4.476,2.806 -6.472,5.164 -1.86,1.146 -4.982,3.384 -5.056,5.82 1.124,1.468 1.626,2.97 2.234,4.704 v 0 c -0.316,5.61801 1.456,4.99401 6.442,4.89801 -1.14,1.822 -2.366,3.564 -3.62,5.31 -1.95,2.246 -3.464,4.796 -5.056,7.3 -3.182,5.058 -6.5,9.462 -10.092,14.184 l -0.804,0.272 c -2.854,3.482 -4.438,8.244 -6.946,12.09 0.062,-2.884 0.094,-5.748 0,-8.632 -0.152,-5.29 -0.606,-10.77 0,-16.034 -4.278,6.658 -7.876,14.308 -9.904,21.966 l -0.172,-0.658 c -0.69,-2.716 -0.326,-5.508 -1.658,-8.056 -2.812,3.078 -0.546,7.956 -1.82,11.414 -2.326,1.824 -3.704,3.838 -4.96,6.498 0.362,13.11001 -0.04,26.34401 -0.64,39.44401 -2.058,-8.594 -3.944,-31.802 -5.008,-35.10001 -1.466,3.81001 -4.786,9.06401 -5.378,12.93801 -1.004,6.558 0.336,12.898 -1.634,19.682 l -0.152,-2.372 c -1.242,0.97 -0.692,3.5 -1.568,4.852 -0.888,5.956 -6.352,24.62201 -2.024,29.02001 l 1.026,-0.056 c 0.982,-1.328 1.022,-2.274 0.998,-3.888 2.54,11.112 6.984,15.086 6.272,27.338 -4.292,-5.588 -5.538,-12.7 -9.37,-18.494 -3.122,10.1 -3.688,19.896 -1.048,30.034 0.382,1.46 5.496,9.346 2.684,9.412 -1.922,-1.014 -3.814,-2.066 -5.696,-3.148 v 6.18601 l 5.696,5.592 -0.786,0.856 c 0.296,2.89 2.728,6.41 -0.85,8.024 -1.37,-0.752 -2.74,-1.49 -4.06,-2.326 1.508,3.706 4.194,6.776 5.696,10.326 -5.51,8.998 8.018,9.652 6.644,16.822 -2.168,-1.12 -4.022,-2.238 -6.51,-2.394 l -0.58,0.476 c 1.212,3.574 5.104,5.87 8.18,7.788 l 0.106,0.944 c 2.112,1.702 5.154,3.652 6.672,5.856 l -0.092,0.576 c -1.6,-0.072 -10.62,-4.306 -6.686,-0.158 3.098,4.66401 7.5,8.32001 11.042,12.63001 1.028,1.378 2.036,2.636 2.66,4.248 l -0.342,0.572 c -2.3,-0.9 -3.438,-2.91 -5.976,-3.28 2.058,3.032 5.576,4.756 7.89,7.506 -6.846,-3.492 -13.43,-7.156 -19.826,-11.44 1.408,2.746 2.824,5.372 4.552,7.934 -0.206,1.33 -0.332,2.17 0,3.506 l -0.486,0.014 c -0.536,-6.728 -2.78,-4.58 -4.492,-8.664 -0.876,-2.09 -0.732,4.084 -0.79,5.038 l -0.504,0.106 c -1.038,2.206 -1.184,4.448 -1.462,6.838 -3.996,-3.73 -9.106,-6.404 -13.392,-9.86 1.374,-0.026 10.618,6.274 12.052,7.594 l 0.588,0.544 c 0.038,-7.076 -1.66,-12.922 -8.058,-15.766 l -0.276,-0.808 c 1.184,0.176 3.7,2.69 4.754,3.524 -1.57,-16.19201 -6.668,-17.95401 -15.372,-31.30601 -8.38,-12.854 -23.376,-43.43601 -22.744,-58.36601 0.294,-0.982 0.308,-1.814 0.212,-2.84 10.33,8.248 15.84,18.246 28.126,27.642 -0.088,-5.064 -1.526,-10.736 -2.462,-15.774 0.614,-23.334 -11.684,-42.03401 -11.934,-70.90801 1.27,-8.674 0.552,-26.22801 3.168,-33.15201 2.02,-0.768 3.486,-1.332 4.866,-3.024 l 0.976,-0.068 c 2.178,1.894 8.68,18.70601 9.84,22.36001 l 0.57,-0.518 c 1.386,0.9 2.382,2.54 3.39,3.858 1.862,-13.02001 6.618,-19.94201 9.452,-31.46801 3.608,-14.66 3.426,-26.278 9.076,-42.08001 1.844,-0.87 4.766,-8.314 5.944,-10.542 9.246,3.156 6.92,-0.208 4.17,11.186 l 0.192,0.106 -0.41,0.728 0.244,-0.106 c 1.028,-4.08 3.034,-8.04 4.67,-11.914 0.6,-3.108 1.304,-7.516 4.174,-9.192 0.93,7.21 1.644,14.442 2.54,21.656 1.148,-2.524 1.142,-5.15 2.088,-7.614 8.798,-9.326 16.32,-19.906 24.89,-29.486 4.756,-5.318 10.938,-9.912 15.132,-15.63401 4.15,-5.656 5.632,-12.712 10.296,-18.166 9.088,-3.418 4.138,-28.214 26.708,-18.13 2.074,4.474 -2.57,9.344 -1.244,14.208 v 2.354 c 3.582,-3.148 6.998,-5.586 11.174,-7.91 v 0 c 0.246,0.008 69.236,-30.86201 77.75,-34.60401 z"
id="path66"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 182.19375,266.87369 c 0.564,-0.782 2.61,-7.412 3.094,-3.452 0.322,2.642 1.102,21.51 -3.094,19.486 -0.152,-5.29 -0.606,-10.77 0,-16.034 z"
id="path67"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 125.81775,310.5497 c 2.45,2.318 5.498,11.792 7.544,15.398 2.698,4.748 6.998,5.738 5.39,11.534 l -0.768,0.906 -0.92,-0.342 c -4.658,-6.078 -8.65,-19.842 -11.246,-27.496 z"
id="path68"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 238.02975,204.78568 c 5.564,-5.62 15.092,-21.80401 23.426,-22.17401 -1.03,1.272 -5.95,6.208 -5.208,7.716 -1.792,1.966 -4.054,3.62801 -5.628,5.75201 -3.67,1.584 -4.516,5.316 -6.108,8.706 2.69,-0.91 5.97,-2.338 8.79,-2.506 -1.89,1.25 -12.68,4.234 -15.272,4.588 v 0 z"
id="path69"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 295.69975,180.57167 h 2.702 c -8.5,7.116 -21.784,5.136 -31.99,7.612 -3.338,1.062 -6.97,1.058 -10.164,2.144 -0.742,-1.508 4.178,-6.444 5.208,-7.716 1.96,-1.942 7.53,-0.964 9.782,0 8.094,-2.064 16.232,-1.644 24.462,-2.04 z"
id="path70"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 261.45575,182.61167 c 1.96,-1.942 7.53,-0.964 9.782,0 -9.012,0.558 -6.586,5.252 -4.826,5.572 -3.338,1.062 -6.97,1.058 -10.164,2.144 -0.742,-1.508 4.178,-6.444 5.208,-7.716 z"
id="path71"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 200.03575,242.78168 c 1.124,1.468 1.626,2.97 2.234,4.704 v 0 c -0.316,5.61801 1.456,4.99401 6.442,4.89801 -1.14,1.822 -2.366,3.564 -3.62,5.31 -1.95,2.246 -3.464,4.796 -5.056,7.3 -3.182,5.058 -6.5,9.462 -10.092,14.184 l -0.804,0.272 c 0.992,-2.136 -0.112,-2.814 -0.734,-4.852 -1.902,-6.224 8.246,-26.224 11.63,-31.81601 z"
id="path72"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 202.26975,247.48568 v 0 c -0.316,5.61801 1.456,4.99401 6.442,4.89801 -1.14,1.822 -2.366,3.564 -3.62,5.31 -1.95,2.246 -3.464,4.796 -5.056,7.3 -0.992,-6.32 1.244,-11.428 2.234,-17.50801 z"
id="path73"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 298.40175,180.57167 -0.042,1.276 c -7.05,4.88 -18.516,5.498 -27.53,13.56001 -1.344,1.2 -2.83,2.678 -4.418,3.494 -4.23,1.326 -8.724,2.754 -13.11,3.378 -2.82,0.168 -6.1,1.596 -8.79,2.506 1.592,-3.39 2.438,-7.122 6.108,-8.706 1.574,-2.124 3.836,-3.78601 5.628,-5.75201 3.194,-1.086 6.826,-1.082 10.164,-2.144 10.206,-2.476 23.49,-0.496 31.99,-7.612 z"
id="path74"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 271.23775,193.48968 c -1.194,1.158 -4.558,3.824 -4.826,5.412 -4.23,1.326 -8.724,2.754 -13.11,3.378 -2.82,0.168 -6.1,1.596 -8.79,2.506 1.592,-3.39 2.438,-7.122 6.108,-8.706 6.902,-0.504 13.82,-1.276 20.618,-2.59 z"
id="path75"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 149.29975,466.26772 c -9.304,-9.342 -10.01,-43.218 -10.518,-57.68401 -0.538,-15.364 -1.234,-63.88401 4.522,-71.25001 l 0.256,0.428 -0.55,-0.498 c 0.858,0.034 1.536,1.384 3.084,1.57 -0.638,1.076 -2.192,1.04 -2.766,2.208 -3.374,6.87 -7.36,60.42401 -3.304,71.67401 l 1.144,0.50401 0.542,-0.48001 c -0.028,-1.786 0.016,-3.3 0.432,-5.04 v 6.18601 l 5.696,5.592 -0.786,0.856 c 0.296,2.89 2.728,6.41 -0.85,8.024 -1.37,-0.752 -2.74,-1.49 -4.06,-2.326 1.508,3.706 4.194,6.776 5.696,10.326 -5.51,8.998 8.018,9.652 6.644,16.822 -2.168,-1.12 -4.022,-2.238 -6.51,-2.394 l -0.58,0.476 c 1.212,3.574 5.104,5.87 8.18,7.788 l 0.106,0.944 c 2.112,1.702 5.154,3.652 6.672,5.856 l -0.092,0.576 c -1.6,-0.072 -10.62,-4.306 -6.686,-0.158 3.098,4.66401 7.5,8.32001 11.042,12.63001 1.028,1.378 2.036,2.636 2.66,4.248 l -0.342,0.572 c -2.3,-0.9 -3.438,-2.91 -5.976,-3.28 2.058,3.032 5.576,4.756 7.89,7.506 -6.846,-3.492 -13.43,-7.156 -19.826,-11.44 1.408,2.746 2.824,5.372 4.552,7.934 -0.206,1.33 -0.332,2.17 0,3.506 l -0.486,0.014 c -0.536,-6.728 -2.78,-4.58 -4.492,-8.664 -0.876,-2.09 -0.732,4.084 -0.79,5.038 l -0.504,0.106 c 0.334,-4.398 -0.07,-7.204 1.72,-11.458 -1.008,-2.202 -1.76,-4.234 -1.72,-6.71201 z"
id="path76"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 149.29975,466.26772 c 2.55,1.562 4.34,4.17401 5.39,6.94401 l -0.242,0.898 c -1.33,0.158 -2.298,-0.53 -3.428,-1.13 -1.008,-2.202 -1.76,-4.234 -1.72,-6.71201 z"
id="path77"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 234.59975,171.88167 c 9.088,-3.418 4.138,-28.214 26.708,-18.13 2.074,4.474 -2.57,9.344 -1.244,14.208 v 2.354 c -1.148,1.816 -5.864,3.458 -7.922,4.874 -14.14,9.736 -15.23,14.912 -24.894,26.40001 -6.982,8.3 -15.26,15.5 -22.134,23.932 -11.878,14.576 -27.774,39.38201 -41.434,51.23801 0.79,-11.36 12.096,-43.94801 11.8,-46.44001 0.6,-3.108 1.304,-7.516 4.174,-9.192 0.93,7.21 1.644,14.442 2.54,21.656 1.148,-2.524 1.142,-5.15 2.088,-7.614 8.798,-9.326 16.32,-19.906 24.89,-29.486 4.756,-5.318 10.938,-9.912 15.132,-15.63401 4.15,-5.656 5.632,-12.712 10.296,-18.166 z"
id="path78"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 306.53575,171.88167 -6.764,-0.428 1.672,-0.284 c -6.714,-7.61 17.512,-9.466 21.164,-11.206 6.186,-2.944 8.754,-8.358 16.164,-11.038 -2.502,2.67 -10.852,4.99 -2.406,7.588 l -0.286,0.044 c 2.342,0.576 6.822,-0.49 7.562,0.282 11.012,-0.444 21.382,3.234 32.396,2.412 -3.822,-2.582 -9.28,-3.286 -13.692,-4.562 l 0.166,-0.49 c 4.176,-1.344 9.568,0.502 13.526,-1.328 2.99,-0.914 6.34,-0.822 9.44,-1.264 43.72,19.62 46.344,31.682 19.526,73.22601 v 0 c -1.554,2.762 -3.848,7.304 -4.686,10.42 l -0.256,0.984 -0.8,0.356 c -0.148,-6.828 6.032,-14.334 5.742,-19.654 3.41,-15.986 -69.354,5.438 -83.98,12.018 -112.918,50.79001 -146.822,194.80204 -68.622,289.88605 2.912,3.538 9.012,12.78601 14.01,12.81601 5.634,0.72 11.242,1.612 16.884,2.268 -0.202,-4.49 -5.588,-11.15401 -7.948,-15.01601 l 0.744,-0.738 c 0.012,-2.102 -1.516,-3.748 -1.268,-5.77 l 0.892,-0.308 c 1.028,2.482 1.052,5.254 3.65,6.816 1.536,3.252 4.578,6.77601 6.57,9.84601 4.044,-3.966 8.118,-7.76801 12.466,-11.40401 1.258,-0.768 2.186,-1.952 3.172,-3.032 1.292,-8.566 1.428,-17.722 1.922,-26.378 -0.138,-1.118 -0.616,-2.868 -0.238,-3.908 l 1.168,0.966 -0.246,-0.612 -0.924,0.544 1.134,-0.23 c 3.66,6.196 9.036,11.464 13.456,17.124 20.682,-19.848 -7.462,-45.92001 -22.146,-59.30801 8.322,2.714 22.978,21.546 26.672,29.42201 2.368,5.048 2.81,14.832 4.236,17.488 3.938,-9.238 -6.242,-21.60201 -4.594,-23.16201 6.228,12.53801 9.19,23.92001 0,35.56001 -11.034,9.136 -29.284,21.156 -36.122,33.99601 -15.95,29.946 -3.004,58.48801 7.948,85.92401 1.766,3.338 5.028,8.098 5.668,11.75001 h -1.106 l -7.45,-10.00201 c -1.728,-2.178 -3.5,-4.33 -5.016,-6.664 -6.324,-4.728 -13.836,-10.324 -21.092,-13.49 -1.626,-0.89 -3.196,-1.934 -4.78,-2.904 -1.312,-1.568 -4.878,-2.91 -6.762,-3.614 -4.274,-4.488 -9.078,-8.416 -13.794,-12.424 -3.644,-3.258 -7.338,-6.40601 -11.126,-9.49601 -9.516,-10.912 -20.848,-17.964 -34.05,-23.62 -3.398,0.208 -6.702,-1.566 -10.05,-2.2 -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 c -1.778,-0.832 -2.898,-1.432 -3.716,-3.304 l 1.262,-2.344 h -1.262 c -2.998,-1.264 -4.654,-5.114 -7.29,-7.02 -3.114,-2.442 -5.858,-6.428 -8.34,-9.526 -7.37,-9.20401 15.16,1.224 16.892,1.472 -1.776,-4.28401 -4.174,-7.85601 -6.946,-11.55201 v 0 c -1.186,-3.19 -1.29,-6.316 -4.994,-7.248 0.668,0.008 0.234,0.036 1.274,-0.272 l -0.462,-1.048 c -0.872,-0.626 -1.716,-1.272 -2.532,-1.97 -2.314,-1.318 -4.576,-1.42 -7.188,-1.558 l 0.348,-0.398 c -4.896,-4.894 -10.688,-6.678 -13.068,-13.884 -0.332,-1.336 -0.206,-2.176 0,-3.506 -1.728,-2.562 -3.144,-5.188 -4.552,-7.934 6.396,4.284 12.98,7.948 19.826,11.44 -2.314,-2.75 -5.832,-4.474 -7.89,-7.506 2.538,0.37 3.676,2.38 5.976,3.28 l 0.342,-0.572 c -0.624,-1.612 -1.632,-2.87 -2.66,-4.248 -3.542,-4.31 -7.944,-7.966 -11.042,-12.63001 -3.934,-4.148 5.086,0.086 6.686,0.158 l 0.092,-0.576 c -1.518,-2.204 -4.56,-4.154 -6.672,-5.856 l -0.106,-0.944 c -3.076,-1.918 -6.968,-4.214 -8.18,-7.788 l 0.58,-0.476 c 2.488,0.156 4.342,1.274 6.51,2.394 1.374,-7.17 -12.154,-7.824 -6.644,-16.822 -1.502,-3.55 -4.188,-6.62 -5.696,-10.326 1.32,0.836 2.69,1.574 4.06,2.326 3.578,-1.614 1.146,-5.134 0.85,-8.024 l 0.786,-0.856 -5.696,-5.592 v -6.18601 c 1.882,1.082 3.774,2.134 5.696,3.148 2.812,-0.066 -2.302,-7.952 -2.684,-9.412 -2.64,-10.138 -2.074,-19.934 1.048,-30.034 3.832,5.794 5.078,12.906 9.37,18.494 0.712,-12.252 -3.732,-16.226 -6.272,-27.338 0.024,1.614 -0.016,2.56 -0.998,3.888 l -1.026,0.056 c -4.328,-4.398 1.136,-23.06401 2.024,-29.02001 0.876,-1.352 0.326,-3.882 1.568,-4.852 l 0.152,2.372 c 1.97,-6.784 0.63,-13.124 1.634,-19.682 0.592,-3.874 3.912,-9.128 5.378,-12.93801 1.064,3.29801 2.95,26.50601 5.008,35.10001 0.6,-13.1 1.002,-26.334 0.64,-39.44401 1.256,-2.66 2.634,-4.674 4.96,-6.498 1.274,-3.458 -0.992,-8.336 1.82,-11.414 1.332,2.548 0.968,5.34 1.658,8.056 l 0.172,0.658 c 2.028,-7.658 5.626,-15.308 9.904,-21.966 -0.606,5.264 -0.152,10.744 0,16.034 0.094,2.884 0.062,5.748 0,8.632 2.508,-3.846 4.092,-8.608 6.946,-12.09 l 0.804,-0.272 c 3.592,-4.722 6.91,-9.126 10.092,-14.184 1.592,-2.504 3.106,-5.054 5.056,-7.3 1.254,-1.746 2.48,-3.488 3.62,-5.31 -4.986,0.096 -6.758,0.72 -6.442,-4.89801 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 0.074,-2.436 3.196,-4.674 5.056,-5.82 1.996,-2.358 2.592,-6.384 6.472,-5.164 5.168,-5.012 8.8,-14.116 16.818,-14.858 0.326,-3.532 2.758,-15.804 7.368,-15.872 l 2.28,3.718 v 2.082 0 c 2.592,-0.354 13.382,-3.338 15.272,-4.588 4.386,-0.624 8.88,-2.052 13.11,-3.378 1.588,-0.816 3.074,-2.294 4.418,-3.494 9.014,-8.06201 20.48,-8.68001 27.53,-13.56001 l 0.042,-1.276 h -2.702 c -7.65,-3.338 -12.068,0.834 -18.448,-0.768 11.644,-3.204 15.88,-5.512 29.284,-7.922 z"
id="path79"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 154.48175,356.6817 c 1.552,0.2 3.084,0.076 4.642,0 -0.404,2.63801 -0.692,5.29001 -1.092,7.92601 -1.188,-2.608 -2.544,-5.248 -3.55,-7.92601 z"
id="path80"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 159.12375,442.51972 c 0.384,2.614 0.992,5.194 1.546,7.778 -3.03,-2.766 -6.444,-5.21 -9.65,-7.778 l 0.538,0.054 c 2.192,0.234 4.934,1.556 6.996,1.18 z"
id="path81"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 175.47975,498.19573 c 0.814,1.764 4.086,6.738 0,5.588 -2.314,-1.318 -4.576,-1.42 -7.188,-1.558 l 0.348,-0.398 c 2.21,-2.024 4.874,-1.53 6.84,-3.632 z"
id="path82"
style="stroke-width:2" />
<path
fill="#ad7214"
d="m 155.57175,466.26772 c 9.084,-1.716 12.038,4.78201 11.562,12.49601 l -0.52,0.134 c -3.542,-4.31 -7.944,-7.966 -11.042,-12.63001 z"
id="path83"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 155.57175,459.04972 c -3.076,-1.918 -6.968,-4.214 -8.18,-7.788 l 0.58,-0.476 c 2.488,0.156 4.342,1.274 6.51,2.394 2.566,1.4 4.326,3.672 6.188,5.87 1.02,1.764 1.71,3.5 2.37,5.424 -2.364,-1.688 -4.912,-4.152 -7.468,-5.424 z"
id="path84"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 180.58775,533.92774 c -3.114,-2.442 -5.858,-6.428 -8.34,-9.526 -7.37,-9.20401 15.16,1.224 16.892,1.472 6.636,13.13 -9.994,0.33 -16.85,-2.24 3.11,3.16 6.322,6.268 8.298,10.294 z"
id="path85"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 266.41175,531.65974 c 5.634,0.72 11.242,1.612 16.884,2.268 -0.584,3.624 -3.86,8.832 -5.208,12.668 -3.562,-5.308 -7.8,-9.892 -11.676,-14.936 z"
id="path86"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 142.14175,426.03172 c 1.32,0.836 2.69,1.574 4.06,2.326 4.29,3.432 12.174,7.82 12.862,13.616 l 0.06,0.546 -0.57,1.234 c -2.062,0.376 -4.804,-0.946 -6.996,-1.18 l -0.538,-0.054 c -1,-2.096 -2.014,-4.15 -3.182,-6.162 -1.502,-3.55 -4.188,-6.62 -5.696,-10.326 z"
id="path87"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 142.14175,407.69971 c 1.882,1.082 3.774,2.134 5.696,3.148 3.018,1.372 5.362,4.13001 7.734,6.39601 0.206,2.976 0.198,5.812 0,8.788 -2.638,-2.122 -5.196,-4.312 -7.734,-6.554 l -5.696,-5.592 z"
id="path88"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 155.57175,484.43773 c 2.938,2.218 18.9,12.614 19.908,13.758 -1.966,2.102 -4.63,1.608 -6.84,3.632 -4.896,-4.894 -10.688,-6.678 -13.068,-13.884 -0.332,-1.336 -0.206,-2.176 0,-3.506 z"
id="path89"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 303.49575,487.94373 c -0.138,-1.118 -0.616,-2.868 -0.238,-3.908 l 1.168,0.966 -0.246,-0.612 -0.924,0.544 1.134,-0.23 c 3.66,6.196 9.036,11.464 13.456,17.124 -2.234,2.422 -5.066,4.484 -7.648,6.516 -1.722,-5.352 -6.16,-14.438 -4.026,-19.786 l -0.84,-0.608 c -0.8,1.028 -0.922,2.05 -1.224,3.294 z"
id="path90"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 343.64175,156.83967 c 11.012,-0.444 21.382,3.234 32.396,2.412 v 0 c 2.758,1.782 6.394,1.874 9.44,3.152 -10.682,1.228 -39.754,-2.68 -41.606,-1.904 0.806,1.616 2.88,2.336 4.224,3.502 l -1.41,0.542 0.34,0.15 -1.298,-0.124 c -4.908,-6.008 -9.214,-5.39 -10.248,-6.48 2.774,-0.232 5.512,-0.324 8.162,-1.25 z"
id="path91"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 376.03775,152.87167 c 2.99,-0.914 6.34,-0.822 9.44,-1.264 43.72,19.62 46.344,31.682 19.526,73.22601 v 0 c 5.832,-22.874 34.842,-43.05801 -2.732,-64.07601 -11.18,-6.254 -18.164,-10.16 -31.452,-6.352 l -0.424,1.2 -0.404,-0.834 c 3.842,4.244 26.77,7.59 30.22,14.342 -1.308,0.37 -18.904,-9.996 -23.724,-10.5 l -0.45,0.638 v 0 c -3.822,-2.582 -9.28,-3.286 -13.692,-4.562 l 0.166,-0.49 c 4.176,-1.344 9.568,0.502 13.526,-1.328 z"
id="path92"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 168.63975,291.53969 c 1.274,-3.458 -0.992,-8.336 1.82,-11.414 1.332,2.548 0.968,5.34 1.658,8.056 l 0.172,0.658 c 2.774,10.994 2.712,19.95201 -1.444,30.43201 -1.604,-9.654 -3.796,-17.92201 -2.206,-27.73201 z"
id="path93"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 149.29975,337.4817 c 0.876,-1.352 0.326,-3.882 1.568,-4.852 l 0.152,2.372 c 1.894,5.472 9.814,16.574 8.104,21.68 -1.558,0.076 -3.09,0.2 -4.642,0 -1.126,-2.77 -2.134,-5.716 -3.462,-8.39 -1.878,5.094 -2.658,8.81 -1.72,14.26601 0.024,1.614 -0.016,2.56 -0.998,3.888 l -1.026,0.056 c -4.328,-4.398 1.136,-23.06401 2.024,-29.02001 z"
id="path94"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 306.53575,171.88167 -6.764,-0.428 1.672,-0.284 c -6.714,-7.61 17.512,-9.466 21.164,-11.206 6.186,-2.944 8.754,-8.358 16.164,-11.038 -2.502,2.67 -10.852,4.99 -2.406,7.588 l -0.286,0.044 c 2.342,0.576 6.822,-0.49 7.562,0.282 -2.65,0.926 -5.388,1.018 -8.162,1.25 1.034,1.09 5.34,0.472 10.248,6.48 -3.348,-0.918 -27.976,0.078 -32.714,1.348 4.33,2.232 9.916,1.048 14.594,3.258 l 0.012,0.634 c -3.474,2.758 -16.412,2.3 -21.084,2.072 z"
id="path95"
style="stroke-width:2" />
<path
fill="#ad7214"
d="m 187.87775,540.94774 c 14.452,-1.578 18.17,9.438 25.354,17.744 17.95,20.75601 34.99,32.52001 57.314,46.64401 2.982,1.888 11.55,9.15 14.164,9.758 -0.954,-3.75 -7.964,-27.508 -9.222,-29.136 -2.72,-3.514 -11.288,-7.96801 -15.268,-11.09401 -12.18,-9.558 -46.938,-41.988 -52.316,-57.27201 l 0.808,-0.238 c 9.448,21.46801 48.068,54.83801 66.636,67.04602 1.412,2.178 10.994,29.386 10.588,32.432 -6.324,-4.728 -13.836,-10.324 -21.092,-13.49 -1.626,-0.89 -3.196,-1.934 -4.78,-2.904 -1.312,-1.568 -4.878,-2.91 -6.762,-3.614 -4.274,-4.488 -9.078,-8.416 -13.794,-12.424 -3.644,-3.258 -7.338,-6.40601 -11.126,-9.49601 -9.516,-10.912 -20.848,-17.964 -34.05,-23.62 -3.398,0.208 -6.702,-1.566 -10.05,-2.2 -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 c -1.778,-0.832 -2.898,-1.432 -3.716,-3.304 l 1.262,-2.344 z"
id="path96"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 189.13975,540.94774 c 5.534,2.624 11.97,2.904 15.952,8.136 -3.688,-0.196 -7.236,-1.452 -10.76,-2.488 h -2.738 c -1.778,-0.832 -2.898,-1.432 -3.716,-3.304 z"
id="path97"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 184.28175,549.08374 c -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 h 2.738 c 3.524,1.036 7.072,2.292 10.76,2.488 1.886,2.01 3.24,4.586 4.692,6.922 -3.318,-1.236 -12.546,-5.238 -15.452,-4.722 v 0 c -3.398,0.208 -6.702,-1.566 -10.05,-2.2 z"
id="path98"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 184.28175,549.08374 c -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 h 2.738 c -4.344,0.788 -4.744,0.478 -1.17,2.97 l -0.606,-0.004 c -4.844,0.006 -0.282,1.608 1.776,1.722 v 0 c -3.398,0.208 -6.702,-1.566 -10.05,-2.2 z"
id="path99"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 228.38175,216.93968 c 0.326,-3.532 2.758,-15.804 7.368,-15.872 l 2.28,3.718 v 2.082 0 c -6.518,12.316 13.27,-2.088 15.158,-2.352 -0.618,2.432 -27.42,25.384 -31.64,31.524 -3.73,5.426 -11.42,18.06801 -16.456,21.65401 1.254,-1.746 2.48,-3.488 3.62,-5.31 -4.986,0.096 -6.758,0.72 -6.442,-4.89801 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 0.074,-2.436 3.196,-4.674 5.056,-5.82 1.996,-2.358 2.592,-6.384 6.472,-5.164 5.168,-5.012 8.8,-14.116 16.818,-14.858 z"
id="path100"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 232.69375,222.27368 v 0 c -2.516,5.136 -7.8,8.384 -11.258,12.894 0.908,-3.178 1.606,-7.628 3.46,-10.334 2.71,0.164 5.344,-1.512 7.798,-2.56 z"
id="path101"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 205.09175,236.96168 c 1.996,-2.358 2.592,-6.384 6.472,-5.164 -1.882,3.976 -3.154,7.958 -2.26,12.41 l 0.746,0.966 c 1.808,0.074 2.558,-0.808 4.2,-1.294 -0.568,2.526 -3.898,6.34801 -5.538,8.50401 -4.986,0.096 -6.758,0.72 -6.442,-4.89801 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 0.074,-2.436 3.196,-4.674 5.056,-5.82 z"
id="path102"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 200.03575,242.78168 c 0.074,-2.436 3.196,-4.674 5.056,-5.82 -1.032,3.436 -2.298,6.974 -2.822,10.524 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 z"
id="path103"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 228.38175,216.93968 c 0.326,-3.532 2.758,-15.804 7.368,-15.872 l 2.28,3.718 v 2.082 c -1.486,1.796 -3.142,3.526 -3.43,5.944 4.566,-0.902 8.72,-2.206 13.04,-3.914 -4.882,4.584 -9.786,9.102 -14.946,13.376 v 0 c -2.454,1.048 -5.088,2.724 -7.798,2.56 0.764,-2.614 2.36,-5.384 3.486,-7.894 z"
id="path104"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 358.50775,173.44367 c 18.416,-4.38 53.464,-10.342 55.298,16.884 -24.86,0.57 -35.762,0.938 -60.484,4.82201 l -0.202,-0.514 c 1.278,-0.93 3.428,-0.886 4.184,-1.712 6.046,-6.58801 1.738,-6.33201 2.402,-12.86401 0.52,-5.102 6.456,-5.5 -0.302,-6.478 z"
id="path105"
style="stroke-width:2" />
<defs
id="defs106">
<linearGradient
id="gradient_7"
gradientUnits="userSpaceOnUse"
x1="141.16791"
y1="268.56354"
x2="265.50784"
y2="226.48077"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#E1AF37"
id="stop105" />
<stop
offset="1"
stop-color="#FCDE74"
id="stop106" />
</linearGradient>
</defs>
<path
fill="url(#gradient_7)"
d="m 208.71175,517.35373 c -86.018,-118.12402 -12.156,-301.82605 129.714,-339.49006 6.44,-1.71 13.438,-3.836 20.082,-4.42 l 0.896,0.138 c 6.758,0.978 0.822,1.376 0.302,6.478 -0.664,6.532 3.644,6.276 -2.402,12.86401 -0.756,0.826 -2.906,0.782 -4.184,1.712 l 0.202,0.514 c -12.89,3.57 -25.456,7.312 -37.754,12.642 -137.6,59.63401 -168.028,233.46204 -63.62,337.58006 7.44,7.418 16.184,13.6 23.4,21.124 0.094,5.944 0.338,11.96801 0,17.90401 -18.568,-12.20801 -57.188,-45.57801 -66.636,-67.04602 z"
id="path106"
style="fill:url(#gradient_7);stroke-width:2" />
</svg>

After

Width:  |  Height:  |  Size: 57 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -172,6 +172,14 @@ ahriman.application.handlers.sign module
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.statistics module
----------------------------------------------
.. automodule:: ahriman.application.handlers.statistics
:members:
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.status module
------------------------------------------

View File

@ -20,6 +20,22 @@ ahriman.core.alpm.pacman module
:no-undoc-members:
:show-inheritance:
ahriman.core.alpm.pacman\_database module
-----------------------------------------
.. automodule:: ahriman.core.alpm.pacman_database
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.alpm.pkgbuild\_parser module
-----------------------------------------
.. automodule:: ahriman.core.alpm.pkgbuild_parser
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.alpm.repo module
-----------------------------

View File

@ -36,6 +36,14 @@ ahriman.core.auth.oauth module
:no-undoc-members:
:show-inheritance:
ahriman.core.auth.pam module
----------------------------
.. automodule:: ahriman.core.auth.pam
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------

View File

@ -4,6 +4,14 @@ ahriman.core.build\_tools package
Submodules
----------
ahriman.core.build\_tools.package\_archive module
-------------------------------------------------
.. automodule:: ahriman.core.build_tools.package_archive
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.build\_tools.sources module
----------------------------------------

View File

@ -28,6 +28,14 @@ ahriman.core.configuration.shell\_interpolator module
:no-undoc-members:
:show-inheritance:
ahriman.core.configuration.shell\_template module
-------------------------------------------------
.. automodule:: ahriman.core.configuration.shell_template
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.configuration.validator module
-------------------------------------------

View File

@ -108,6 +108,22 @@ ahriman.core.database.migrations.m012\_last\_commit\_sha module
:no-undoc-members:
:show-inheritance:
ahriman.core.database.migrations.m013\_dependencies module
----------------------------------------------------------
.. automodule:: ahriman.core.database.migrations.m013_dependencies
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.database.migrations.m014\_auditlog module
------------------------------------------------------
.. automodule:: ahriman.core.database.migrations.m014_auditlog
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------

View File

@ -28,6 +28,22 @@ ahriman.core.database.operations.changes\_operations module
:no-undoc-members:
:show-inheritance:
ahriman.core.database.operations.dependencies\_operations module
----------------------------------------------------------------
.. automodule:: ahriman.core.database.operations.dependencies_operations
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.database.operations.event\_operations module
---------------------------------------------------------
.. automodule:: ahriman.core.database.operations.event_operations
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.database.operations.logs\_operations module
--------------------------------------------------------

View File

@ -44,6 +44,14 @@ ahriman.core.formatters.configuration\_printer module
:no-undoc-members:
:show-inheritance:
ahriman.core.formatters.event\_stats\_printer module
----------------------------------------------------
.. automodule:: ahriman.core.formatters.event_stats_printer
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.formatters.package\_printer module
-----------------------------------------------
@ -52,6 +60,14 @@ ahriman.core.formatters.package\_printer module
:no-undoc-members:
:show-inheritance:
ahriman.core.formatters.package\_stats\_printer module
------------------------------------------------------
.. automodule:: ahriman.core.formatters.package_stats_printer
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.formatters.patch\_printer module
---------------------------------------------

View File

@ -60,6 +60,14 @@ ahriman.core.report.report\_trigger module
:no-undoc-members:
:show-inheritance:
ahriman.core.report.rss module
------------------------------
.. automodule:: ahriman.core.report.rss
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.report.telegram module
-----------------------------------

View File

@ -12,6 +12,14 @@ ahriman.core.repository.cleaner module
:no-undoc-members:
:show-inheritance:
ahriman.core.repository.event\_logger module
--------------------------------------------
.. automodule:: ahriman.core.repository.event_logger
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.repository.executor module
---------------------------------------

View File

@ -60,6 +60,14 @@ ahriman.core.util module
:no-undoc-members:
:show-inheritance:
ahriman.core.utils module
-------------------------
.. automodule:: ahriman.core.utils
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------

View File

@ -12,6 +12,14 @@ ahriman.core.status.client module
:no-undoc-members:
:show-inheritance:
ahriman.core.status.local\_client module
----------------------------------------
.. automodule:: ahriman.core.status.local_client
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.status.watcher module
----------------------------------

View File

@ -60,6 +60,30 @@ ahriman.models.counters module
:no-undoc-members:
:show-inheritance:
ahriman.models.dependencies module
----------------------------------
.. automodule:: ahriman.models.dependencies
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.event module
---------------------------
.. automodule:: ahriman.models.event
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.filesystem\_package module
-----------------------------------------
.. automodule:: ahriman.models.filesystem_package
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.internal\_status module
--------------------------------------
@ -84,6 +108,14 @@ ahriman.models.log\_record\_id module
:no-undoc-members:
:show-inheritance:
ahriman.models.metrics\_timer module
------------------------------------
.. automodule:: ahriman.models.metrics_timer
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.migration module
-------------------------------
@ -140,6 +172,14 @@ ahriman.models.pacman\_synchronization module
:no-undoc-members:
:show-inheritance:
ahriman.models.pkgbuild module
------------------------------
.. automodule:: ahriman.models.pkgbuild
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.pkgbuild\_patch module
-------------------------------------
@ -204,6 +244,14 @@ ahriman.models.result module
:no-undoc-members:
:show-inheritance:
ahriman.models.scan\_paths module
---------------------------------
.. automodule:: ahriman.models.scan_paths
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.sign\_settings module
------------------------------------

View File

@ -44,6 +44,14 @@ ahriman.web.schemas.counters\_schema module
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.dependencies\_schema module
-----------------------------------------------
.. automodule:: ahriman.web.schemas.dependencies_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.error\_schema module
----------------------------------------
@ -52,6 +60,22 @@ ahriman.web.schemas.error\_schema module
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.event\_schema module
----------------------------------------
.. automodule:: ahriman.web.schemas.event_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.event\_search\_schema module
------------------------------------------------
.. automodule:: ahriman.web.schemas.event_search_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.file\_schema module
---------------------------------------
@ -156,6 +180,14 @@ ahriman.web.schemas.package\_status\_schema module
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.package\_version\_schema module
---------------------------------------------------
.. automodule:: ahriman.web.schemas.package_version_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.pagination\_schema module
---------------------------------------------

View File

@ -0,0 +1,21 @@
ahriman.web.views.v1.auditlog package
=====================================
Submodules
----------
ahriman.web.views.v1.auditlog.events module
-------------------------------------------
.. automodule:: ahriman.web.views.v1.auditlog.events
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ahriman.web.views.v1.auditlog
:members:
:no-undoc-members:
:show-inheritance:

View File

@ -12,6 +12,14 @@ ahriman.web.views.v1.packages.changes module
:no-undoc-members:
:show-inheritance:
ahriman.web.views.v1.packages.dependencies module
-------------------------------------------------
.. automodule:: ahriman.web.views.v1.packages.dependencies
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.views.v1.packages.logs module
-----------------------------------------

View File

@ -7,6 +7,7 @@ Subpackages
.. toctree::
:maxdepth: 4
ahriman.web.views.v1.auditlog
ahriman.web.views.v1.distributed
ahriman.web.views.v1.packages
ahriman.web.views.v1.service

View File

@ -0,0 +1,21 @@
ahriman.web.views.v2.packages package
=====================================
Submodules
----------
ahriman.web.views.v2.packages.logs module
-----------------------------------------
.. automodule:: ahriman.web.views.v2.packages.logs
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ahriman.web.views.v2.packages
:members:
:no-undoc-members:
:show-inheritance:

View File

@ -0,0 +1,18 @@
ahriman.web.views.v2 package
============================
Subpackages
-----------
.. toctree::
:maxdepth: 4
ahriman.web.views.v2.packages
Module contents
---------------
.. automodule:: ahriman.web.views.v2
:members:
:no-undoc-members:
:show-inheritance:

View File

@ -12,8 +12,8 @@ Packages have strict rules of importing:
Full dependency diagram:
.. image:: ahriman-architecture.svg
:target: _images/ahriman-architecture.svg
.. image:: _static/architecture.svg
:target: _static/architecture.svg
:alt: architecture
``ahriman.application`` package
@ -32,7 +32,7 @@ This package contains application (aka executable) related classes and everythin
This package contains everything required for the most of application actions and it is separated into several packages:
* ``ahriman.core.alpm`` package controls pacman related functions. It provides wrappers for ``pyalpm`` library and safe calls for repository tools (``repo-add`` and ``repo-remove``). Also this package contains ``ahriman.core.alpm.remote`` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC).
* ``ahriman.core.alpm`` package controls pacman related functions. It provides wrappers for ``pyalpm`` library and safe calls for repository tools (``repo-add`` and ``repo-remove``). Also this package contains ``ahriman.core.alpm.remote`` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC) and some other helpers.
* ``ahriman.core.auth`` package provides classes for authorization methods used by web mostly. Base class is ``ahriman.core.auth.Auth`` which must be instantiated by ``load`` method.
* ``ahriman.core.build_tools`` is a package which provides wrapper for ``devtools`` commands.
* ``ahriman.core.configuration`` contains extension for standard ``configparser`` library and some validation related classes.
@ -192,6 +192,7 @@ Idea is to add package to a build queue from which it will be handled automatica
* If supplied argument is file, then application moves the file to the directory with built packages. Same rule applies for directory, but in this case it copies every package-like file from the specified directory.
* If supplied argument is directory and there is ``PKGBUILD`` file there, it will be treated as local package. In this case it will queue this package to build and copy source files (``PKGBUILD`` and ``.SRCINFO``) to caches.
* If supplied argument looks like URL (i.e. it has scheme - e.g. ``http://`` which is neither ``data`` nor ``file``), it tries to download the package from the specified remote source.
* If supplied argument is not file then application tries to lookup for the specified name in AUR and clones it into the directory with manual updates. This scenario can also handle package dependencies which are missing in repositories.
This logic can be overwritten by specifying the ``source`` parameter, which is partially useful if you would like to add package from AUR, but there is local directory cloned from AUR. Also official repositories calls are hidden behind explicit source definition.
@ -206,10 +207,20 @@ Remove packages
This flow removes package from filesystem, updates repository database and also runs synchronization and reporting methods.
Check outdated packages
^^^^^^^^^^^^^^^^^^^^^^^
There are few ways for packages to be marked as out-of-date and hence requiring rebuild. Those are following:
#. User requested update of the package. It can be caused by calling ``package-add`` subcommand (or ``package-update`` with arguments).
#. The most common way for packages to be marked as out-of-dated is that the version in AUR (or the official repositories) is newer than in the repository.
#. In addition to the above, if package is named as VCS (e.g. has suffix ``-git``) and the last update was more than specified threshold ago, the service will also try to fetch sources and check if the revision is newer than the built one.
#. In addition, there is ability to check if the dependencies of the package have been updated (e.g. if linked library has been renamed or the modules directory - e.g. in case of python and ruby packages - has been changed). And if so, the package will be marked as out-of-dated as well.
Update packages
^^^^^^^^^^^^^^^
This feature is divided into to the following stages: check AUR for updates and run rebuild for required packages. Whereas check does not do anything except for check itself, update flow is the following:
This feature is divided into to the following stages: check AUR for updates and run rebuild for required packages. The package update flow is the following:
#. Process every built package first. Those packages are usually added manually.
#. Run sync and report methods.
@ -259,6 +270,24 @@ The application is able to automatically bump package release (``pkgrel``) durin
#. If it has ``major.minor`` notation (e.g. ``1.1``), then increment last part by 1, e.g. ``1.1 -> 1.2``, ``1.0.1 -> 1.0.2``.
#. If ``pkgrel`` is a number (e.g. ``1``), then append 1 to the end of the string, e.g. ``1 -> 1.1``.
Implicit dependencies resolution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In addition to the depends/optional/make/check depends lists the server also handles implicit dependencies. After success build, the application traverse through the build tree and finds
* Libraries to which the binaries (ELF-files) are linked. To do so, the ``NEEDED`` section of the ELF-files are read.
* Directories which contains files of the package, but do not belong to this package. This case covers, for example, python and ruby submodules.
Having the initial dependencies tree, the application is looking for packages which contains those (both files and directories) paths and creates the initial packages list. After that, the packages list is reduced in the following way:
* From any leaf exclude the package itself and possible debug packages.
* If the entry (i.e. file or directory) belongs to the package which is in base group, it will be removed.
* If there is a package which depends on the another package which provide the same entry, the package will be removed.
* After that, if there is a package which *optionally* depends on the another package in the remaining list, the package will be removed.
* And finally, if there is any path, which is the child of the entry, and it contains the same package, the package from the smaller entry will be removed.
All those implicit dependencies are stored in the database and extracted on each check. In case if any of the repository packages doesn't contain any entry anymore (e.g. so version has been changed or modules directory has been changed), the dependent package will be marked as out-of-dated.
Core functions reference
------------------------
@ -346,6 +375,24 @@ There are several supported synchronization providers, currently they are ``rsyn
``github`` provider authenticates through basic auth, API key with repository write permissions is required. There will be created a release with the name of the architecture in case if it does not exist; files will be uploaded to the release assets. It also stores array of files and their MD5 checksums in release body in order to upload only changed ones. According to the GitHub API in case if there is already uploaded asset with the same name (e.g. database files), asset will be removed first.
PKGBUILD parsing
^^^^^^^^^^^^^^^^
The application provides a house-made shell parser ``ahriman.core.alpm.pkgbuild_parser.PkgbuildParser`` to process PKGBUILDs and extract package data from them. It relies on the ``shlex.shlex`` parser with some configuration tweaks and adds some token post-processing.
#. During the parser process, firstly, it extract next token from the source file (basically, the word) and tries to match it to the variable assignment. If so, then just processes accordingly.
#. If it is not an assignment, the parser checks if the token was quoted.
#. If it wasn't then the parser tries to match the array starts (two consecutive tokens like ``array=`` and ``(``) or it is function (``function``, ``()`` and ``{``).
#. The arrays are processed until the next closing bracket ``)``. After extraction, the parser tries to expand an array according to bash rules (``prefix{first,second}suffix`` constructions).
#. The functions are just read until the closing bracket ``}`` and then reread whole text from the input string without a tokenization.
All extracted fields are packed as ``ahriman.models.pkgbuild_patch.PkgbuildPatch`` and then can be used as ``ahriman.models.pkgbuild.Pkgbuild`` instance.
The PKGBUILD class also provides some additional functions on top of that:
* Ability to extract fields defined inside ``package*()`` functions, which are in particular used for the multipackages.
* Shell substitution, which supports constructions ``$var`` (including ``${var}``), ``${var#(#)pattern}``, ``${var%(%)pattern}`` and ``${var/(/)pattern/replacement}`` (including ``#pattern`` and ``%pattern``).
Additional features
^^^^^^^^^^^^^^^^^^^
@ -366,7 +413,7 @@ Web application requires the following python packages to be installed:
* Additional web features also require ``aiohttp-apispec`` (autogenerated documentation), ``aiohttp_cors`` (CORS support, required by documentation).
* In addition, authorization feature requires ``aiohttp_security``, ``aiohttp_session`` and ``cryptography``.
* In addition to base authorization dependencies, OAuth2 also requires ``aioauth-client`` library.
* In addition if you would like to disable authorization for local access (recommended way in order to run the application itself with reporting support), the ``requests-unixsocket`` library is required.
* In addition if you would like to disable authorization for local access (recommended way in order to run the application itself with reporting support), the ``requests-unixsocket2`` library is required.
Middlewares
^^^^^^^^^^^

View File

@ -72,7 +72,9 @@ html_theme = "sphinx_rtd_theme"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = []
html_static_path = ["_static"]
html_logo = "_static/logo.svg"
add_module_names = False

View File

@ -17,14 +17,33 @@ There are two variable types which have been added to default ones, they are pat
Path values, except for casting to ``pathlib.Path`` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to ``ahriman.ini.d/logging.ini`` and root configuration path is ``/etc/ahriman.ini``, the value will be expanded to ``/etc/ahriman.ini.d/logging.ini``. In order to disable path expand, use the full path, e.g. ``/etc/ahriman.ini.d/logging.ini``.
Configuration allows string interpolation from environment variables, e.g.:
Configuration allows string interpolation from the same configuration file, e.g.:
.. code-block:: ini
[section]
key = ${anoher_key}
another_key = value
will read value for the ``key`` option from ``another_key`` in the same section. In case if the cross-section reference is required, the ``${section:another_key}`` notation must be used. It also allows string interpolation from environment variables, e.g.:
.. code-block:: ini
[section]
key = $SECRET
will try to read value from ``SECRET`` environment variable. In case if the required environment variable wasn't found, it will keep original value (i.e. ``$SECRET`` in the example). Dollar sign can be set as ``$$``.
will try to read value from ``SECRET`` environment variable. In case if the required environment variable wasn't found, it will keep original value (i.e. ``$SECRET`` in the example). Dollar sign can be set as ``$$``. All those interpolations will be applied in succession and - expected to be - recursively, e.g. the following configuration:
.. code-block:: ini
[section1]
key = ${section2:key}
[section2]
key = ${home}
home = $HOME
will eventually lead ``key`` option in section ``section1`` to be set to the value of ``HOME`` environment variable (if available).
There is also additional subcommand which will allow to validate configuration and print found errors. In order to do so, run ``service-config-validate`` subcommand, e.g.:
@ -53,6 +72,7 @@ libalpm and AUR related configuration. Group name can refer to architecture, e.g
* ``mirror`` - package database mirror used by pacman for synchronization, string, required. This option supports standard pacman substitutions with ``$arch`` and ``$repo``. Note that the mentioned mirror should contain all repositories which are set by ``alpm.repositories`` option.
* ``repositories`` - list of pacman repositories, used for package search, space separated list of strings, required.
* ``root`` - root for alpm library, string, required. In the most cases it must point to the system root.
* ``sync_files_database`` - download files database from mirror, boolean, required.
* ``use_ahriman_cache`` - use local pacman package cache instead of system one, boolean, required. With this option enabled you might want to refresh database periodically (available as additional flag for some subcommands). If set to ``no``, databases must be synchronized manually.
``auth`` group
@ -60,15 +80,17 @@ libalpm and AUR related configuration. Group name can refer to architecture, e.g
Base authorization settings. ``OAuth`` provider requires ``aioauth-client`` library to be installed.
* ``target`` - specifies authorization provider, string, optional, default ``disabled``. Allowed values are ``disabled``, ``configuration``, ``oauth``.
* ``target`` - specifies authorization provider, string, optional, default ``disabled``. Allowed values are ``disabled``, ``configuration``, ``oauth``, ``pam``.
* ``allow_read_only`` - allow requesting status APIs without authorization, boolean, required.
* ``client_id`` - OAuth2 application client ID, string, required in case if ``oauth`` is used.
* ``client_secret`` - OAuth2 application client secret key, string, required in case if ``oauth`` is used.
* ``cookie_secret_key`` - secret key which will be used for cookies encryption, string, optional. It must be 32 bytes URL-safe base64-encoded and can be generated as following ``base64.urlsafe_b64encode(os.urandom(32)).decode("utf8")``. If not set, it will be generated automatically; note, however, that in this case, all sessions will be automatically invalidated during the service restart.
* ``full_access_group`` - name of the secondary group (e.g. ``wheel``) to be used as admin group in the service, string, required in case if ``pam`` is used.
* ``max_age`` - parameter which controls both cookie expiration and token expiration inside the service in seconds, integer, optional, default is 7 days.
* ``oauth_icon`` - OAuth2 login button icon, string, optional, default is ``google``. Must be valid `Bootstrap icon <https://icons.getbootstrap.com/>`__ name.
* ``oauth_provider`` - OAuth2 provider class name as is in ``aioauth-client`` (e.g. ``GoogleClient``, ``GithubClient`` etc), string, required in case if ``oauth`` is used.
* ``oauth_scopes`` - scopes list for OAuth2 provider, which will allow retrieving user email (which is used for checking user permissions), e.g. ``https://www.googleapis.com/auth/userinfo.email`` for ``GoogleClient`` or ``user:email`` for ``GithubClient``, space separated list of strings, required in case if ``oauth`` is used.
* ``permit_root_login`` - allow login as root user, boolean, optional, default ``no``.
* ``salt`` - additional password hash salt, string, optional.
Authorized users are stored inside internal database, if any of external providers (e.g. ``oauth``) are used, the password field for non-service users must be empty.
@ -81,8 +103,10 @@ Build related configuration. Group name can refer to architecture, e.g. ``build:
* ``archbuild_flags`` - additional flags passed to ``archbuild`` command, space separated list of strings, optional.
* ``build_command`` - default build command, string, required.
* ``ignore_packages`` - list packages to ignore during a regular update (manual update will still work), space separated list of strings, optional.
* ``include_debug_packages`` - distribute debug packages, boolean, optional, default ``yes``.
* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional.
* ``makechrootpkg_flags`` - additional flags passed to ``makechrootpkg`` command, space separated list of strings, optional.
* ``scan_paths`` - paths to be used for implicit dependencies scan, space separated list of strings, optional. If any of those paths is matched against the path, it will be added to the allowed list.
* ``triggers`` - list of ``ahriman.core.triggers.Trigger`` class implementation (e.g. ``ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger``) which will be loaded and run at the end of processing, space separated list of strings, optional. You can also specify triggers by their paths, e.g. ``/usr/lib/python3.10/site-packages/ahriman/core/report/report.py.ReportTrigger``. Triggers are run in the order of definition.
* ``triggers_known`` - optional list of ``ahriman.core.triggers.Trigger`` class implementations which are not run automatically and used only for trigger discovery and configuration validation.
* ``vcs_allowed_age`` - maximal age in seconds of the VCS packages before their version will be updated with its remote source, integer, optional, default is 7 days.
@ -128,7 +152,7 @@ Web server settings. This feature requires ``aiohttp`` libraries to be installed
* ``port`` - port to bind, integer, optional.
* ``service_only`` - disable status routes (including logs), boolean, optional, default ``no``.
* ``static_path`` - path to directory with static files, string, required.
* ``templates`` - path to templates directories, space separated list of strings, required.
* ``templates`` - path to templates directories, space separated list of paths, required.
* ``unix_socket`` - path to the listening unix socket, string, optional. If set, server will create the socket on the specified address which can (and will) be used by application. Note, that unlike usual host/port configuration, unix socket allows to perform requests without authorization.
* ``unix_socket_unsafe`` - set unsafe (o+w) permissions to unix socket, boolean, optional, default ``yes``. This option is enabled by default, because it is supposed that unix socket is created in safe environment (only web service is supposed to be used in unsafe), but it can be disabled by configuration.
* ``wait_timeout`` - wait timeout in seconds, maximum amount of time to be waited before lock will be free, integer, optional.
@ -246,11 +270,12 @@ Section name must be either ``email`` (plus optional architecture name, e.g. ``e
* ``password`` - SMTP password to authenticate, string, optional.
* ``port`` - SMTP port for sending emails, integer, required.
* ``receivers`` - SMTP receiver addresses, space separated list of strings, required.
* ``rss_url`` - link to RSS feed, string, optional.
* ``sender`` - SMTP sender address, string, required.
* ``ssl`` - SSL mode for SMTP connection, one of ``ssl``, ``starttls``, ``disabled``, optional, default ``disabled``.
* ``template`` - Jinja2 template name, string, required.
* ``template_full`` - Jinja2 template name for full package description index, string, optional.
* ``templates`` - path to templates directories, space separated list of strings, required.
* ``templates`` - path to templates directories, space separated list of paths, required.
* ``user`` - SMTP user to authenticate, string, optional.
``html`` type
@ -261,9 +286,10 @@ Section name must be either ``html`` (plus optional architecture name, e.g. ``ht
* ``type`` - type of the report, string, optional, must be set to ``html`` if exists.
* ``homepage`` - link to homepage, string, optional.
* ``link_path`` - prefix for HTML links, string, required.
* ``path`` - path to html report file, string, required.
* ``path`` - path to HTML report file, string, required.
* ``rss_url`` - link to RSS feed, string, optional.
* ``template`` - Jinja2 template name, string, required.
* ``templates`` - path to templates directories, space separated list of strings, required.
* ``templates`` - path to templates directories, space separated list of paths, required.
``remote-call`` type
^^^^^^^^^^^^^^^^^^^^
@ -276,6 +302,20 @@ Section name must be either ``remote-call`` (plus optional architecture name, e.
* ``manual`` - update manually built packages, boolean, optional, default ``no``.
* ``wait_timeout`` - maximum amount of time in seconds to be waited before remote process will be terminated, integer, optional, default ``-1``.
``rss`` type
^^^^^^^^^^^^
Section name must be either ``rss`` (plus optional architecture name, e.g. ``rss:x86_64``) or random name with ``type`` set.
* ``type`` - type of the report, string, optional, must be set to ``rss`` if exists.
* ``homepage`` - link to homepage, string, optional.
* ``link_path`` - prefix for HTML links, string, required.
* ``max_entries`` - maximal amount of entries to be included to the report, negative means no limit, integer, optional, default ``-1``.
* ``path`` - path to generated RSS file, string, required.
* ``rss_url`` - link to RSS feed, string, optional.
* ``template`` - Jinja2 template name, string, required.
* ``templates`` - path to templates directories, space separated list of paths, required.
``telegram`` type
^^^^^^^^^^^^^^^^^
@ -286,9 +326,10 @@ Section name must be either ``telegram`` (plus optional architecture name, e.g.
* ``chat_id`` - telegram chat id, either string with ``@`` or integer value, required.
* ``homepage`` - link to homepage, string, optional.
* ``link_path`` - prefix for HTML links, string, required.
* ``rss_url`` - link to RSS feed, string, optional.
* ``template`` - Jinja2 template name, string, required.
* ``template_type`` - ``parse_mode`` to be passed to telegram API, one of ``MarkdownV2``, ``HTML``, ``Markdown``, string, optional, default ``HTML``.
* ``templates`` - path to templates directories, space separated list of strings, required.
* ``templates`` - path to templates directories, space separated list of paths, required.
* ``timeout`` - HTTP request timeout in seconds, integer, optional, default is ``30``.
``upload`` group
@ -338,7 +379,7 @@ Requires ``rsync`` package to be installed. Do not forget to configure ssh for u
* ``type`` - type of the upload, string, optional, must be set to ``rsync`` if exists.
* ``command`` - rsync command to run, space separated list of string, required.
* ``remote`` - remote server to rsync (e.g. ``1.2.3.4:path/to/sync``), string, required.
* ``remote`` - remote server to rsync (e.g. ``ahriman@10.0.0.1:/srv/repo``), string, required.
``s3`` type
^^^^^^^^^^^

File diff suppressed because it is too large Load Diff

35
docs/faq/backup.rst Normal file
View File

@ -0,0 +1,35 @@
Backup and restore
------------------
The service provides several commands aim to do easy repository backup and restore. If you would like to move repository from the server ``server1.example.com`` to another ``server2.example.com`` you have to perform the following steps:
#.
On the source server ``server1.example.com`` run ``repo-backup`` command, e.g.:
.. code-block:: shell
ahriman repo-backup /tmp/repo.tar.gz
This command will pack all configuration files together with database file into the archive specified as command line argument (i.e. ``/tmp/repo.tar.gz``). In addition it will also archive ``cache`` directory (the one which contains local clones used by e.g. local packages) and ``.gnupg`` of the ``ahriman`` user.
#.
Copy created archive from source server ``server1.example.com`` to target ``server2.example.com``.
#.
Install package as usual on the target server ``server2.example.com`` if you didn't yet.
#.
Extract archive e.g. by using subcommand:
.. code-block:: shell
ahriman repo-restore /tmp/repo.tar.gz
An additional argument ``-o``/``--output`` can be used to specify extraction root (``/`` by default).
#.
Rebuild repository:
.. code-block:: shell
sudo -u ahriman ahriman repo-rebuild --from-database

320
docs/faq/distributed.rst Normal file
View File

@ -0,0 +1,320 @@
Distributed builds
------------------
The service allows to run build on multiple machines and collect packages on main node. There are several ways to achieve it, this section describes officially supported methods.
Remote synchronization and remote server call
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This setup requires at least two instances of the service:
#. Web service (with opt-in authorization enabled), later will be referenced as **master** node.
#. Application instances responsible for build, later will be referenced as **worker** nodes.
In this example the following settings are assumed:
* Repository architecture is ``x86_64``.
* Master node address is ``master.example.com``.
Master node configuration
"""""""""""""""""""""""""
The only requirements for the master node is that API must be available for worker nodes to call (e.g. port must be exposed to internet, or local network in case of VPN, etc) and file upload must be enabled:
.. code-block:: ini
[web]
enable_archive_upload = yes
In addition, the following settings are recommended for the master node:
*
As it has been mentioned above, it is recommended to enable authentication (see :doc:`How to enable basic authorization <web>`) and create system user which will be used later. Later this user (if any) will be referenced as ``worker-user``.
*
In order to be able to spawn multiple processes at the same time, wait timeout must be configured:
.. code-block:: ini
[web]
wait_timeout = 0
Worker nodes configuration
""""""""""""""""""""""""""
#.
First of all, in this setup you need to split your repository into chunks manually, e.g. if you have repository on master node with packages ``A``, ``B`` and ``C``, you need to split them between all available workers, as example:
* Worker #1: ``A``.
* Worker #2: ``B`` and ``C``.
Hint: ``repo-tree`` subcommand provides ``--partitions`` argument.
#.
Each worker must be configured to upload files to master node:
.. code-block:: ini
[upload]
target = remote-service
[remote-service]
#.
Worker must be configured to access web on master node:
.. code-block:: ini
[status]
address = https://master.example.com
username = worker-user
password = very-secure-password
As it has been mentioned above, ``${status:address}`` must be available for workers. In case if unix socket is used, it can be passed in the same option as usual. Optional ``${status:username}``/``${status:password}`` can be supplied in case if authentication was enabled on master node.
#.
Each worker must call master node on success:
.. code-block:: ini
[report]
target = remote-call
[remote-call]
manual = yes
After success synchronization (see above), the built packages will be put into directory, from which they will be read during manual update, thus ``${remote-call:manual}`` flag is required.
#.
Change order of trigger runs. This step is required, because by default the report trigger is called before the upload trigger and we would like to achieve the opposite:
.. code-block:: ini
[build]
triggers = ahriman.core.gitremote.RemotePullTrigger ahriman.core.upload.UploadTrigger ahriman.core.report.ReportTrigger ahriman.core.gitremote.RemotePushTrigger
In addition, the following settings are recommended for workers:
*
You might want to wait until report trigger will be completed; in this case the following option must be set:
.. code-block:: ini
[remote-call]
wait_timeout = 0
Dependency management
"""""""""""""""""""""
By default worker nodes don't know anything about master nodes packages, thus it will try to build each dependency by its own. However, using ``AHRIMAN_REPOSITORY_SERVER`` docker variable (or ``--server`` flag for setup command), it is possible to specify address of the master node for devtools configuration.
Repository and packages signing
"""""""""""""""""""""""""""""""
You can sign packages on worker nodes and then signatures will be synced to master node. In order to do so, you need to configure worker node as following, e.g.:
.. code-block:: ini
[sign]
target = package
key = 8BE91E5A773FB48AC05CC1EDBED105AED6246B39
Note, however, that in this case, signatures will not be validated on master node and just will be copied to repository tree.
If you would like to sign only database files (aka repository sign), it has to be configured only on master node as usual, e.g.:
.. code-block:: ini
[sign]
target = repository
key = 8BE91E5A773FB48AC05CC1EDBED105AED6246B39
Double node minimal docker example
""""""""""""""""""""""""""""""""""
Master node config (``master.ini``) as:
.. code-block:: ini
[auth]
target = configuration
[web]
enable_archive_upload = yes
wait_timeout = 0
Command to run master node:
.. code-block:: shell
docker run --privileged -p 8080:8080 -e AHRIMAN_PORT=8080 -v master.ini:/etc/ahriman.ini.d/overrides.ini arcan1s/ahriman:latest web
The user ``worker-user`` has been created additionally. Worker node config (``worker.ini``) as:
.. code-block:: ini
[status]
address = http://172.17.0.1:8080
username = worker-user
password = very-secure-password
[upload]
target = remote-service
[remote-service]
[report]
target = remote-call
[remote-call]
manual = yes
wait_timeout = 0
[build]
triggers = ahriman.core.gitremote.RemotePullTrigger ahriman.core.upload.UploadTrigger ahriman.core.report.ReportTrigger ahriman.core.gitremote.RemotePushTrigger
The address above (``http://172.17.0.1:8080``) is somewhat available for worker container.
Command to run worker node:
.. code-block:: shell
docker run --privileged -v worker.ini:/etc/ahriman.ini.d/overrides.ini -it arcan1s/ahriman:latest package-add ahriman --now
The command above will successfully build ``ahriman`` package, upload it on master node and, finally, will update master node repository.
Check proof-of-concept setup `here <https://github.com/arcan1s/ahriman/tree/master/recipes/distributed-manual>`__.
Addition of new package and repository update
"""""""""""""""""""""""""""""""""""""""""""""
Just run on worker command as usual, the built packages will be automatically uploaded to master node. Note that automatic update process must be disabled on master node.
Package removal
"""""""""""""""
This action must be done in two steps:
#. Remove package on worker.
#. Remove package on master node.
Delegate builds to remote workers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This setup heavily uses upload feature described above and, in addition, also delegates build process automatically to build machines. Same as above, there must be at least two instances available (**master** and **worker**), however, all **worker** nodes must be run in the web service mode.
Master node configuration
"""""""""""""""""""""""""
In addition to the configuration above, the worker list must be defined in configuration file (``${build:workers}`` option), i.e.:
.. code-block:: ini
[build]
workers = https://worker1.example.com https://worker2.example.com
[web]
enable_archive_upload = yes
wait_timeout = 0
In the example above, ``https://worker1.example.com`` and ``https://worker2.example.com`` are remote **worker** node addresses available for **master** node.
In case if authentication is required (which is recommended way to setup it), it can be set by using ``status`` section as usual.
Worker nodes configuration
""""""""""""""""""""""""""
It is required to point to the master node repository, otherwise internal dependencies will not be handled correctly. In order to do so, the ``--server`` argument (or ``AHRIMAN_REPOSITORY_SERVER`` environment variable for docker images) can be used.
Also, in case if authentication is enabled, the same user with the same password must be created for all workers.
It is also recommended to set ``${web:wait_timeout}`` to infinite in case of multiple conflicting runs and ``${web:service_only}`` to ``yes`` in order to disable status endpoints.
Other settings are the same as mentioned above.
Triple node minimal docker example
""""""""""""""""""""""""""""""""""
In this example, all instances are run on the same machine with address ``172.17.0.1`` with ports available outside of container. Master node config (``master.ini``) as:
.. code-block:: ini
[auth]
target = configuration
[status]
username = builder-user
password = very-secure-password
[build]
workers = http://172.17.0.1:8081 http://172.17.0.1:8082
[web]
enable_archive_upload = yes
wait_timeout = 0
Command to run master node:
.. code-block:: shell
docker run --privileged -p 8080:8080 -e AHRIMAN_PORT=8080 -v master.ini:/etc/ahriman.ini.d/overrides.ini arcan1s/ahriman:latest web
Worker nodes (applicable for all workers) config (``worker.ini``) as:
.. code-block:: ini
[auth]
target = configuration
[status]
address = http://172.17.0.1:8080
username = builder-user
password = very-secure-password
[upload]
target = remote-service
[remote-service]
[report]
target = remote-call
[remote-call]
manual = yes
wait_timeout = 0
[web]
service_only = yes
[build]
triggers = ahriman.core.upload.UploadTrigger ahriman.core.report.ReportTrigger
Command to run worker nodes (considering there will be two workers, one is on ``8081`` port and other is on ``8082``):
.. code-block:: shell
docker run --privileged -p 8081:8081 -e AHRIMAN_PORT=8081 -v worker.ini:/etc/ahriman.ini.d/overrides.ini arcan1s/ahriman:latest web
docker run --privileged -p 8082:8082 -e AHRIMAN_PORT=8082 -v worker.ini:/etc/ahriman.ini.d/overrides.ini arcan1s/ahriman:latest web
Unlike the previous setup, it doesn't require to mount repository root for **worker** nodes, because they don't use it anyway.
Check proof-of-concept setup `here <https://github.com/arcan1s/ahriman/tree/master/recipes/distributed>`__.
Addition of new package, package removal, repository update
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
In all scenarios, update process must be run only on **master** node. Unlike the manually distributed packages described above, automatic update must be enabled only for **master** node.
Automatic worker nodes discovery
""""""""""""""""""""""""""""""""
Instead of setting ``${build:workers}`` option explicitly it is also possible to configure services to load worker list dynamically. To do so, the ``ahriman.core.distributed.WorkerLoaderTrigger`` and ``ahriman.core.distributed.WorkerTrigger`` must be used for **master** and **worker** nodes respectively. See recipes for more details.
Known limitations
"""""""""""""""""
* Workers don't support local packages. However, it is possible to build custom packages by providing sources by using ``ahriman.core.gitremote.RemotePullTrigger`` trigger.
* No dynamic nodes discovery. In case if one of worker nodes is unavailable, the build process will fail.
* No pkgrel bump on conflicts.
* The identical user must be created for all workers. However, the **master** node user can be different from this one.

115
docs/faq/docker.rst Normal file
View File

@ -0,0 +1,115 @@
Docker image
------------
We provide official images which can be found under:
* docker registry ``arcan1s/ahriman``;
* ghcr.io registry ``ghcr.io/arcan1s/ahriman``.
These images are totally identical.
Docker image is being updated on each commit to master as well as on each version. If you would like to use last (probably unstable) build you can use ``edge`` tag or ``latest`` for any tagged versions; otherwise you can use any version tag available.
The default action (in case if no arguments provided) is ``repo-update``. Basically the idea is to run container, e.g.:
.. code-block:: shell
docker run --privileged -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
``--privileged`` flag is required to make mount possible inside container. In order to make data available outside of container, you would need to mount local (parent) directory inside container by using ``-v /path/to/local/repo:/var/lib/ahriman`` argument, where ``/path/to/local/repo`` is a path to repository on local machine. In addition, you can pass own configuration overrides by using the same ``-v`` flag, e.g.:
.. code-block:: shell
docker run --privileged -v /path/to/local/repo:/var/lib/ahriman -v /path/to/overrides/overrides.ini:/etc/ahriman.ini.d/10-overrides.ini arcan1s/ahriman:latest
The action can be specified during run, e.g.:
.. code-block:: shell
docker run --privileged -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest package-add ahriman --now
For more details please refer to the docker FAQ.
Environment variables
^^^^^^^^^^^^^^^^^^^^^
The following environment variables are supported:
* ``AHRIMAN_ARCHITECTURE`` - architecture of the repository, default is ``x86_64``.
* ``AHRIMAN_DEBUG`` - if set all commands will be logged to console.
* ``AHRIMAN_FORCE_ROOT`` - force run ahriman as root instead of guessing by subcommand.
* ``AHRIMAN_HOST`` - host for the web interface, default is ``0.0.0.0``.
* ``AHRIMAN_MULTILIB`` - if set (default) multilib repository will be used, disabled otherwise.
* ``AHRIMAN_OUTPUT`` - controls logging handler, e.g. ``syslog``, ``console``. The name must be found in logging configuration. Note that if ``syslog`` handler is used you will need to mount ``/dev/log`` inside container because it is not available there.
* ``AHRIMAN_PACKAGER`` - packager name from which packages will be built, default is ``ahriman bot <ahriman@example.com>``.
* ``AHRIMAN_PACMAN_MIRROR`` - override pacman mirror server if set.
* ``AHRIMAN_PORT`` - HTTP server port if any, default is empty.
* ``AHRIMAN_POSTSETUP_COMMAND`` - if set, the command which will be called (as root) after the setup command, but before any other actions.
* ``AHRIMAN_PRESETUP_COMMAND`` - if set, the command which will be called (as root) right before the setup command.
* ``AHRIMAN_REPOSITORY`` - repository name, default is ``aur-clone``.
* ``AHRIMAN_REPOSITORY_SERVER`` - optional override for the repository URL. Useful if you would like to download packages from remote instead of local filesystem.
* ``AHRIMAN_REPOSITORY_ROOT`` - repository root. Because of filesystem rights it is required to override default repository root. By default, it uses ``ahriman`` directory inside ahriman's home, which can be passed as mount volume.
* ``AHRIMAN_UNIX_SOCKET`` - full path to unix socket which is used by web server, default is empty. Note that more likely you would like to put it inside ``AHRIMAN_REPOSITORY_ROOT`` directory (e.g. ``/var/lib/ahriman/ahriman/ahriman-web.sock``) or to ``/run/ahriman``.
* ``AHRIMAN_USER`` - ahriman user, usually must not be overwritten, default is ``ahriman``.
* ``AHRIMAN_VALIDATE_CONFIGURATION`` - if set (default) validate service configuration.
You can pass any of these variables by using ``-e`` argument, e.g.:
.. code-block:: shell
docker run --privileged -e AHRIMAN_PORT=8080 -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
Daemon service
^^^^^^^^^^^^^^
There is special ``repo-daemon`` subcommand which emulates systemd timer and will perform repository update periodically:
.. code-block:: shell
docker run --privileged -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest repo-daemon
This command uses same rules as ``repo-update``, thus, e.g. requires ``--privileged`` flag. Check also `examples <https://github.com/arcan1s/ahriman/tree/master/recipes/daemon>`__.
Web service setup
^^^^^^^^^^^^^^^^^
For that you would need to have web container instance running forever; it can be achieved by the following command:
.. code-block:: shell
docker run --privileged -p 8080:8080 -e AHRIMAN_PORT=8080 -e AHRIMAN_UNIX_SOCKET=/var/lib/ahriman/ahriman/ahriman-web.sock -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
Note about ``AHRIMAN_PORT`` environment variable which is required in order to enable web service. An additional port bind by ``-p 8080:8080`` is required to pass docker port outside of container.
The ``AHRIMAN_UNIX_SOCKET`` variable is not required, however, highly recommended as it can be used for interprocess communications. If you set this variable you would like to be sure that this path is available outside of container if you are going to use multiple docker instances.
If you are using ``AHRIMAN_UNIX_SOCKET`` variable, for every next container run it has to be passed also, e.g.:
.. code-block:: shell
docker run --privileged -e AHRIMAN_UNIX_SOCKET=/var/lib/ahriman/ahriman/ahriman-web.sock -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
Otherwise, you would need to pass ``AHRIMAN_PORT`` and mount container network to the host system (``--net=host``), e.g.:
.. code-block:: shell
docker run --privileged --net=host -e AHRIMAN_PORT=8080 -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
Simple server with authentication can be found in `examples <https://github.com/arcan1s/ahriman/tree/master/recipes/web>`__ too.
Mutli-repository web service
""""""""""""""""""""""""""""
Idea is pretty same as to just run web service. However, it is required to run setup commands for each repository, except for one which is specified by ``AHRIMAN_REPOSITORY`` and ``AHRIMAN_ARCHITECTURE`` variables.
In order to create configuration for additional repositories, the ``AHRIMAN_POSTSETUP_COMMAND`` variable should be used, e.g.:
.. code-block:: shell
docker run --privileged -p 8080:8080 -e AHRIMAN_PORT=8080 -e AHRIMAN_UNIX_SOCKET=/var/lib/ahriman/ahriman/ahriman-web.sock -e AHRIMAN_POSTSETUP_COMMAND="ahriman --architecture x86_64 --repository aur-clone-v2 service-setup --build-as-user ahriman --packager 'ahriman bot <ahriman@example.com>'" -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
The command above will also create configuration for the repository named ``aur-clone-v2``.
Note, however, that the command above is only required in case if the service is going to be used to run subprocesses. Otherwise, everything else (web interface, status, etc) will be handled as usual.
Configuration `example <https://github.com/arcan1s/ahriman/tree/master/recipes/multirepo>`__.

12
docs/faq/examples.rst Normal file
View File

@ -0,0 +1,12 @@
Use cases
---------
There is a collection of some specific recipes which can be found in `the repository <https://github.com/arcan1s/ahriman/tree/master/recipes>`__.
Most of them can be run (``AHRIMAN_PASSWORD`` environment variable is required in the most setups) as simple as:
.. code-block:: shell
AHRIMAN_PASSWORD=demo docker compose up
Note, however, they are just an examples of specific configuration for specific cases and they are never intended to be used as is in real environment.

427
docs/faq/general.rst Normal file
View File

@ -0,0 +1,427 @@
General topics
--------------
What is the purpose of the project
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This project has been created in order to maintain self-hosted Arch Linux user repository without manual intervention - checking for updates and building packages.
How to install ahriman
^^^^^^^^^^^^^^^^^^^^^^
TL;DR
.. code-block:: shell
yay -S ahriman
ahriman -a x86_64 -r aur-clone service-setup --packager "ahriman bot <ahriman@example.com>"
systemctl enable --now ahriman@x86_64-aur-clone.timer
Long answer
"""""""""""
The idea is to install the package as usual, create working directory tree, create configuration for ``sudo`` and ``devtools``. Detailed description of the setup instruction can be found :doc:`here </setup>`.
Run as daemon
"""""""""""""
The alternative way (though not recommended) is to run service instead of timer:
.. code-block:: shell
systemctl enable --now ahriman-daemon@x86_64-aur-clone
How to validate settings
^^^^^^^^^^^^^^^^^^^^^^^^
There is special command which can be used in order to validate current configuration:
.. code-block:: shell
ahriman service-config-validate --exit-code
This command will print found errors, based on `cerberus <https://docs.python-cerberus.org/>`__, e.g.:
.. code-block:: shell
auth
ssalt: unknown field
target: none or more than one rule validate
oneof definition 0: unallowed value mapping
oneof definition 1: field 'salt' is required
oneof definition 2: unallowed value mapping
oneof definition 2: field 'salt' is required
oneof definition 2: field 'client_id' is required
oneof definition 2: field 'client_secret' is required
gitremote
pull_url: unknown field
If an additional flag ``--exit-code`` is supplied, the application will return non-zero exit code, which can be used partially in scripts.
What does "architecture specific" mean / How to configure for different architectures
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some sections can be configured per architecture. The service will merge architecture specific values into common settings. In order to specify settings for specific architecture you must point it in section name.
For example, the section
.. code-block:: ini
[build]
build_command = extra-x86_64-build
states that default build command is ``extra-x86_64-build``. But if there is section
.. code-block:: ini
[build:i686]
build_command = extra-i686-build
the ``extra-i686-build`` command will be used for ``i686`` architecture. You can also override settings for different repositories and architectures; in this case section names will be ``build:aur-clone`` (repository name only) and ``build:aur-clone:i686`` (both repository name and architecture).
How to generate build reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Normally you would probably like to generate only one report for the specific type, e.g. only one email report. In order to do so you will need to have the following configuration:
.. code-block:: ini
[report]
target = email
[email]
...
or in case of multiple architectures and *different* reporting settings:
.. code-block:: ini
[report]
target = email
[email:i686]
...
[email:x86_64]
...
But for some cases you would like to have multiple different reports with the same type (e.g. sending different templates to different addresses). For these cases you will need to specify section name in target and type in section, e.g. the following configuration can be used:
.. code-block:: ini
[report]
target = email_1 email_2
[email_1]
type = email
...
[email_2]
type = email
...
How to add new package
^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: shell
sudo -u ahriman ahriman package-add ahriman --now
``--now`` flag is totally optional and just run ``repo-update`` subcommand after the registering the new package. Thus the extended flow is the following:
.. code-block:: shell
sudo -u ahriman ahriman package-add ahriman
sudo -u ahriman ahriman repo-update
How to build package from local PKGBUILD
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TL;DR
.. code-block:: shell
sudo -u ahriman ahriman package-add /path/to/local/directory/with/PKGBUILD --now
Before using this command you will need to create local directory and put ``PKGBUILD`` there. These packages will be stored locally and *will be ignored* during automatic update; in order to update the package you will need to run ``package-add`` command again.
How to copy package from another repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As simple as add package from archive. Considering case when you would like to copy package ``package`` with version ``ver-rel`` from repository ``source-repository`` to ``target-respository`` (same architecture), the command will be following:
.. code-block:: shell
sudo -u ahriman ahriman -r target-repository package-add /var/lib/ahriman/repository/source-repository/x86_64/package-ver-rel-x86_64.pkg.tar.zst
In addition, you can remove source package as usual later.
This feature in particular useful if for managing multiple repositories like ``[testing]`` and ``[extra]``.
How to fetch PKGBUILDs from remote repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For that purpose you could use ``RemotePullTrigger`` trigger. To do so you will need to configure trigger as following:
.. code-block:: ini
[remote-pull]
target = gitremote
[gitremote]
pull_url = https://github.com/username/repository
During the next application run it will fetch repository from the specified URL and will try to find packages there which can be used as local sources.
This feature can be also used to build packages which are not listed in AUR, the example of the feature use can be found `here <https://github.com/arcan1s/ahriman/tree/master/recipes/pull>`__.
How to push updated PKGBUILDs to remote repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For that purpose you'd need to use another trigger called ``RemotePushTrigger``. Configure trigger as following:
.. code-block:: ini
[remote-push]
target = gitremote
[gitremote]
push_url = https://github.com/username/repository
Unlike ``RemotePullTrigger`` trigger, the ``RemotePushTrigger`` more likely will require authorization. It is highly recommended to use application tokens for that instead of using your password (e.g. for GitHub you can generate tokens `here <https://github.com/settings/tokens>`__ with scope ``public_repo``). Authorization can be supplied by using authorization part of the URL, e.g. ``https://key:token@github.com/username/repository``.
How to change PKGBUILDs before build
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Well it is supported also. The recommended way is to patch specific function, e.g. by running
.. code-block:: shell
sudo -u ahriman ahriman patch-add ahriman version
This command will prompt for new value of the PKGBUILD variable ``version``. You can also write it to file and read from it:
.. code-block:: shell
sudo -u ahriman ahriman patch-add ahriman version version.patch
The command also supports arrays, but in this case you need to specify full array, e.g.
.. code-block:: shell
sudo -u ahriman ahriman patch-add ahriman depends
Post new function or variable value below. Press Ctrl-D to finish:
(python python-aiohttp)
^D
will set depends PKGBUILD variable (exactly) to array ``["python", "python-aiohttp"]``.
Alternatively you can create full-diff patches, which are calculated by using ``git diff`` from current PKGBUILD master branch:
#.
Clone sources from AUR.
#.
Make changes you would like to (e.g. edit ``PKGBUILD``, add external patches).
#.
Run command
.. code-block:: shell
sudo -u ahriman ahriman patch-set-add /path/to/local/directory/with/PKGBUILD
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
It is also possible to create simple patch during package addition, e.g.:
.. code-block:: shell
sudo -u ahriman ahriman package-add ahriman --variable PKGEXT=.pkg.tar.xz
The ``--variable`` argument accepts variables in shell like format: quotation and lists are supported as usual, but functions are not. This feature is useful in particular in order to override specific makepkg variables during build.
How to build package from official repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is the same as adding any other package, but due to restrictions you must specify source explicitly, e.g.:
.. code-block:: shell
sudo -u ahriman ahriman package-add pacman --source repository
This feature is heavily depends on local pacman cache. In order to use this feature it is recommended to either run ``pacman -Sy`` before the interaction or use internal application cache with ``--refresh`` flag.
Package build fails because it cannot validate PGP signature of source files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TL;DR
.. code-block:: shell
sudo -u ahriman ahriman service-key-import ...
How to update VCS packages
^^^^^^^^^^^^^^^^^^^^^^^^^^
Normally the service handles VCS packages correctly. The version is updated in clean chroot, no additional actions are required.
How to review changes before build
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this scenario, the update process must be separated into several stages. First, it is required to check updates:
.. code-block:: shell
sudo -u ahriman ahriman repo-check
During the check process, the service will generate changes from the last known commit and will send it to remote service. In order to verify source files changes, the web interface or special subcommand can be used:
.. code-block:: shell
ahriman package-changes ahriman
After validation, the operator can run update process with approved list of packages, e.g.:
.. code-block:: shell
sudo -u ahriman ahriman repo-update ahriman
How to remove package
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: shell
sudo -u ahriman ahriman package-remove ahriman
Also, there is command ``repo-remove-unknown`` which checks packages in AUR and local storage and removes ones which have been removed.
Remove commands also remove any package files (patches, caches etc).
How to sign repository
^^^^^^^^^^^^^^^^^^^^^^
Repository sign feature is available in several configurations. The recommended way is just to sign repository database file by single key instead of trying to sign each package. However, the steps are pretty same, just configuration is a bit different. For more details about options kindly refer to :doc:`configuration reference </configuration>`.
#.
First you would need to create the key on your local machine:
.. code-block:: shell
gpg --full-generate-key
This command will prompt you for several questions. Most of them may be left default, but you will need to fill real name and email address with some data. Because at the moment the service doesn't support passphrases, it must be left blank.
#.
The command above will generate key and print its fingerprint, something like ``8BE91E5A773FB48AC05CC1EDBED105AED6246B39``. Copy it.
#.
Export your private key by using the fingerprint above:
.. code-block:: shell
gpg --export-secret-keys -a 8BE91E5A773FB48AC05CC1EDBED105AED6246B39 > repository-key.gpg
#.
Copy the specified key to the build machine (i.e. where the service is running).
#.
Import the specified key to the service user:
.. code-block:: shell
sudo -u ahriman gpg --import repository-key.gpg
Don't forget to remove the key from filesystem after import.
#.
Change trust level to ``ultimate``:
.. code-block:: shell
sudo -u ahriman gpg --edit-key 8BE91E5A773FB48AC05CC1EDBED105AED6246B39
The command above will drop you into gpg shell, in which you will need to type ``trust``, choose ``5 = I trust ultimately``, confirm and exit ``quit``.
#.
Proceed with service configuration according to the :doc:`configuration </configuration>`:
.. code-block:: ini
[sign]
target = repository
key = 8BE91E5A773FB48AC05CC1EDBED105AED6246B39
How to rebuild packages after library update
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TL;DR
.. code-block:: shell
sudo -u ahriman ahriman repo-rebuild --depends-on python
You can even rebuild the whole repository (which is particular useful in case if you would like to change packager) if you do not supply ``--depends-on`` option. This action will automatically increment ``pkgrel`` value; in case if you don't want to, the ``--no-increment`` option has to be supplied.
However, note that you do not need to rebuild repository in case if you just changed signing option, just use ``repo-sign`` command instead.
Automated broken dependencies detection
"""""""""""""""""""""""""""""""""""""""
After the success build the application extracts all linked libraries and used directories and stores them in database. During the check process, the application extracts pacman databases and checks if file names have been changed (e.g. new python release caused ``/usr/lib/python3.x`` directory renaming to ``/usr/lib/python3.y`` or soname for a linked library has been changed). In case if broken dependencies have been detected, the package will be added to the rebuild queue.
In order to disable this check completely, the ``--no-check-files`` flag can be used.
In addition, there is possibility to control paths which will be used for checking, by using option ``${build:scan_paths}``, which supports regular expressions. Leaving ``${build:scan_paths}`` blank will effectively disable any check too.
How to install built packages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Add the following lines to your ``pacman.conf``:
.. code-block:: ini
[repository]
Server = file:///var/lib/ahriman/repository/$repo/$arch
(You might need to add ``SigLevel`` option according to the pacman documentation.)
How to serve repository
^^^^^^^^^^^^^^^^^^^^^^^
Easy. For example, nginx configuration (without SSL) will look like:
.. code-block::
server {
listen 80;
server_name repo.example.com;
location / {
autoindex on;
root /var/lib/ahriman/repository;
}
}
Example of the status page configuration is the following (status service is using 8080 port):
.. code-block::
server {
listen 80;
server_name builds.example.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarder-Proto $scheme;
proxy_pass http://127.0.0.1:8080;
}
}
Some more examples can be found in configuration `recipes <https://github.com/arcan1s/ahriman/tree/master/recipes>`__.

17
docs/faq/index.rst Normal file
View File

@ -0,0 +1,17 @@
FAQ
===
.. toctree::
:maxdepth: 2
general
docker
non-x86_64-setup
synchronization
reporting
distributed
maintenance-packages
web
backup
examples
misc

View File

@ -0,0 +1,73 @@
Maintenance packages
--------------------
Generate keyring package
^^^^^^^^^^^^^^^^^^^^^^^^
The application provides special plugin which generates keyring package. This plugin heavily depends on ``sign`` group settings, however it is possible to override them. The minimal package can be generated in the following way:
#.
Edit configuration:
.. code-block:: ini
[keyring]
target = keyring-generator
By default it will use ``${sign:key}`` as trusted key and all other keys as packagers ones. For all available options refer to :doc:`configuration </configuration>`.
#.
Create package source files:
.. code-block:: shell
sudo -u ahriman ahriman repo-create-keyring
This command will generate PKGBUILD, revoked and trusted listings and keyring itself and will register the package in database.
#.
Build new package as usual:
.. code-block:: shell
sudo -u ahriman ahriman package-add aur-clone-keyring --source local --now
where ``aur-clone`` is your repository name.
This plugin might have some issues, in case of any of them, kindly create `new issue <https://github.com/arcan1s/ahriman/issues/new/choose>`__.
Generate mirrorlist package
^^^^^^^^^^^^^^^^^^^^^^^^^^^
The application provides special plugin which generates mirrorlist package also. It is possible to distribute this package as usual later. The package can be generated in the following way:
#.
Edit configuration:
.. code-block:: ini
[mirrorlist]
target = mirrorlist-generator
[mirrorlist-generator]
servers = https://repo.example.com/$arch
The ``${mirrorlist-generator:servers}`` must contain list of available mirrors, the ``$arch`` and ``$repo`` variables are supported. For more options kindly refer to :doc:`configuration </configuration>`.
#.
Create package source files:
.. code-block:: shell
sudo -u ahriman ahriman repo-create-mirrorlist
This command will generate PKGBUILD and mirrorlist file and will register the package in database.
#.
Build new package as usual:
.. code-block:: shell
sudo -u ahriman ahriman package-add aur-clone-mirrorlist --source local --now
where ``aur-clone`` is your repository name.

100
docs/faq/misc.rst Normal file
View File

@ -0,0 +1,100 @@
Other topics
------------
How does it differ from %another-manager%?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Short answer - I do not know. Also for some references credits to `Alad <https://github.com/AladW>`__, he `did <https://wiki.archlinux.org/title/User:Alad/Local_repo_tools>`__ really good investigation of existing alternatives.
`arch-repo-manager <https://github.com/Martchus/arch-repo-manager>`__
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Looks actually pretty good, in case if I would find it, I would probably didn't start this project; the most of features (like web interface or additional helpers) are already implemented or planned to be. However, this project seems to be at early alpha stage (as for Nov 2022), written in C++ (not pro or con) and misses documentation.
`archrepo2 <https://github.com/lilydjwg/archrepo2>`__
"""""""""""""""""""""""""""""""""""""""""""""""""""""
Don't know, haven't tried it. But it lacks of documentation at least.
* ``ahriman`` has web interface.
* ``archrepo2`` doesn't have synchronization and reporting.
* ``archrepo2`` actively uses direct shell calls and ``yaourt`` components.
* ``archrepo2`` has constantly running process instead of timer process (it is not pro or con).
`repoctl <https://github.com/cassava/repoctl>`__
""""""""""""""""""""""""""""""""""""""""""""""""
* ``ahriman`` has web interface.
* ``repoctl`` does not have reporting feature.
* ``repoctl`` does not support local packages and patches.
* Some actions are not fully automated in ``repoctl`` (e.g. package update still requires manual intervention for the build itself).
* ``repoctl`` has better AUR interaction features. With colors!
* ``repoctl`` has much easier configuration and even completion.
* ``repoctl`` is able to store old packages.
* Ability to host repository from same command in ``repoctl`` vs external services (e.g. nginx) in ``ahriman``.
`repod <https://gitlab.archlinux.org/archlinux/repod>`__
""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Official tool provided by distribution, has clean logic, but it is just a helper for ``repo-add``, e.g. it doesn't work with AUR and all packages builds have to be handled separately.
`repo-scripts <https://github.com/arcan1s/repo-scripts>`__
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Though originally I've created ahriman by trying to improve the project, it still lacks a lot of features:
* ``ahriman`` has web interface.
* ``ahriman`` has better reporting with template support.
* ``ahriman`` has more synchronization features (there was only ``rsync`` based).
* ``ahriman`` supports local packages and patches.
* ``repo-scripts`` doesn't have dependency management.
...and so on. ``repo-scripts`` also has bad architecture and bad quality code and uses out-of-dated ``yaourt`` and ``package-query``.
`toolbox <https://github.com/chaotic-aur/toolbox>`__
""""""""""""""""""""""""""""""""""""""""""""""""""""
It is automation tools for ``repoctl`` mentioned above. Except for using shell it looks pretty cool and also offers some additional features like patches, remote synchronization (isn't it?) and reporting.
How to check service logs
^^^^^^^^^^^^^^^^^^^^^^^^^
By default, the service writes logs to ``journald`` which can be accessed by using ``journalctl`` command (logs are written to the journal of the user under which command is run). In order to retrieve logs for the process you can use the following command:
.. code-block:: shell
sudo journalctl SYSLOG_IDENTIFIER=ahriman
You can also ask to forward logs to ``stderr``, just set ``--log-handler`` flag, e.g.:
.. code-block:: shell
ahriman --log-handler console ...
You can even configure logging as you wish, but kindly refer to python ``logging`` module `configuration <https://docs.python.org/3/library/logging.config.html>`__.
The application uses java concept to log messages, e.g. class ``Application`` imported from ``ahriman.application.application`` package will have logger called ``ahriman.application.application.Application``. In order to e.g. change logger name for whole application package it is possible to change values for ``ahriman.application`` package; thus editing ``ahriman`` logger configuration will change logging for whole application (unless there are overrides for another logger).
Html customization
^^^^^^^^^^^^^^^^^^
It is possible to customize html templates. In order to do so, create files somewhere (refer to Jinja2 documentation and the service source code for available parameters) and prepend ``templates`` with value pointing to this directory.
In addition, default html templates supports style customization out-of-box. In order to customize style, just put file named ``user-style.jinja2`` to the templates directory.
Web API extension
^^^^^^^^^^^^^^^^^
The application loads web views dynamically, so it is possible relatively easy extend its API. In order to do so:
#. Create view class which is derived from ``ahriman.web.views.base.BaseView`` class.
#. Create implementation for this class.
#. Put file into ``ahriman.web.views`` package.
#. Restart application.
For more details about implementation and possibilities, kindly refer to module documentation and source code and `aiohttp documentation <https://docs.aiohttp.org/en/stable/>`__.
I did not find my question
^^^^^^^^^^^^^^^^^^^^^^^^^^
`Create an issue <https://github.com/arcan1s/ahriman/issues>`__ with type **Question**.

View File

@ -0,0 +1,99 @@
Non-x86_64 architecture setup
-----------------------------
The following section describes how to setup ahriman with architecture different from x86_64, as example i686. For most cases you have base repository available, e.g. archlinux32 repositories for i686 architecture; in case if base repository is not available, steps are a bit different, however, idea remains the same.
The example of setup with docker compose can be found `here <https://github.com/arcan1s/ahriman/tree/master/recipes/i686>`__.
Physical server setup
^^^^^^^^^^^^^^^^^^^^^
In this example we are going to use files and packages which are provided by official repositories of the used architecture. Note, that versions might be different, thus you need to find correct versions on the distribution web site, e.g. `archlinux32 packages <https://www.archlinux32.org/packages/>`__.
#.
First, considering having base Arch Linux system, we need to install keyring for the specified repositories, e.g.:
.. code-block:: shell
wget https://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
pacman -U archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
#.
In order to run ``devtools`` scripts for custom architecture they also need specific ``makepkg`` configuration, it can be retrieved by installing the ``devtools`` package of the distribution, e.g.:
.. code-block:: shell
wget https://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.2-any.pkg.tar.zst
pacman -U devtools-20221208-1.2-any.pkg.tar.zst
Alternatively, you can create your own ``makepkg`` configuration and save it as ``/usr/share/devtools/makepkg.conf.d/i686.conf``.
#.
Setup repository as usual:
.. code-block:: shell
ahriman -a i686 service-setup --mirror 'https://de.mirror.archlinux32.org/$arch/$repo'--no-multilib ...
In addition to usual options, you need to specify the following options:
* ``--mirror`` - link to the mirrors which will be used instead of official repositories.
* ``--no-multilib`` - in the example we are using i686 architecture for which multilib repository doesn't exist.
#.
That's all Folks!
Docker container setup
^^^^^^^^^^^^^^^^^^^^^^
There are two possible ways to achieve same setup, by using docker container. The first one is just mount required files inside container and run it as usual (with specific environment variables). Another one is to create own container based on official one:
#.
Clone official container as base:
.. code-block:: dockerfile
FROM arcan1s/ahriman:latest
#.
Init pacman keys. This command is required in order to populate distribution keys:
.. code-block:: dockerfile
RUN pacman-key --init
#.
Install packages as it was described above:
.. code-block:: dockerfile
RUN pacman --noconfirm -Sy wget
RUN wget https://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.2-any.pkg.tar.zst && pacman --noconfirm -U devtools-20221208-1.2-any.pkg.tar.zst
RUN wget https://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20230705-1.0-any.pkg.tar.zst && pacman --noconfirm -U archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
#.
At that point you should have full ``Dockerfile`` like:
.. code-block:: dockerfile
FROM arcan1s/ahriman:latest
RUN pacman-key --init
RUN pacman --noconfirm -Sy wget
RUN wget https://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.2-any.pkg.tar.zst && pacman --noconfirm -U devtools-20221208-1.2-any.pkg.tar.zst
RUN wget https://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20230705-1.0-any.pkg.tar.zst && pacman --noconfirm -U archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
#.
After that you can build you own container, e.g.:
.. code-block:: shell
docker build --tag ahriman-i686:latest
#.
Now you can run locally built container as usual with passing environment variables for setup command:
.. code-block:: shell
docker run --privileged -p 8080:8080 -e AHRIMAN_ARCHITECTURE=i686 -e AHRIMAN_PACMAN_MIRROR='https://de.mirror.archlinux32.org/$arch/$repo' -e AHRIMAN_MULTILIB= ahriman-i686:latest

119
docs/faq/reporting.rst Normal file
View File

@ -0,0 +1,119 @@
Reporting
---------
How to report by email
^^^^^^^^^^^^^^^^^^^^^^
#.
Install dependencies:
.. code-block:: shell
yay -S --asdeps python-jinja
#.
Configure the service:
.. code-block:: ini
[report]
target = email
[email]
host = smtp.example.com
link_path = http://example.com/aur-clone/x86_64
password = ...
port = 465
receivers = me@example.com
sender = me@example.com
user = me@example.com
How to generate index page
^^^^^^^^^^^^^^^^^^^^^^^^^^
#.
Install dependencies:
.. code-block:: shell
yay -S --asdeps python-jinja
#.
Configure the service:
.. code-block:: ini
[report]
target = html
[html]
path = ${repository:root}/repository/aur-clone/x86_64/index.html
link_path = http://example.com/aur-clone/x86_64
Having this configuration, the generated ``index.html`` will be also automatically synced to remote services (e.g. S3).
How to generate RSS feed for index page
"""""""""""""""""""""""""""""""""""""""
In addition to previous steps, the following configuration is required:
.. code-block:: ini
[report]
target = html rss
[html]
rss_url = ${html:link_path}/rss.xml
[rss]
link_path = ${html:link_path}
path = ${repository:root}/repository/ahriman-demo/x86_64/rss.xml
rss_url = ${html:link_path}/rss.xml
With the appended configuration, the service fill also generate ``rss.xml``, link it to generated ``index.html`` and put it together.
How to post build report to telegram
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#.
It still requires additional dependencies:
.. code-block:: shell
yay -S --asdeps python-jinja
#.
Register bot in telegram. You can do it by starting chat with `@BotFather <https://t.me/botfather>`__. For more details please refer to `official documentation <https://core.telegram.org/bots>`__.
#.
Optionally (if you want to post message in chat):
#. Create telegram channel.
#. Invite your bot into the channel.
#. Make your channel public
#.
Get chat id if you want to use by numerical id or just use id prefixed with ``@`` (e.g. ``@ahriman``). If you are not using chat the chat id is your user id. If you don't want to make channel public you can use `this guide <https://stackoverflow.com/a/33862907>`__.
#.
Configure the service:
.. code-block:: ini
[report]
target = telegram
[telegram]
api_key = aaAAbbBBccCC
chat_id = @ahriman
link_path = http://example.com/aur-clone/x86_64
``${api_key}`` is the one sent by `@BotFather <https://t.me/botfather>`__, ``${chat_id}`` is the value retrieved from previous step.
If you did everything fine you should receive the message with the next update. Quick credentials check can be done by using the following command:
.. code-block:: shell
curl 'https://api.telegram.org/bot${api_key}/sendMessage?chat_id=${chat_id}&text=hello'
(replace ``${chat_id}`` and ``${api_key}`` with the values from configuration).

View File

@ -0,0 +1,131 @@
Remote synchronization
----------------------
How to sync repository to another server
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are several choices:
#.
Easy and cheap, just share your local files through the internet, e.g. for ``nginx``:
.. code-block::
server {
location / {
autoindex on;
root /var/lib/ahriman/repository/;
}
}
#.
You can also upload your packages using ``rsync`` to any available server. In order to use it you would need to configure ahriman first:
.. code-block:: ini
[upload]
target = rsync
[rsync]
remote = 192.168.0.1:/srv/repo
After that just add ``/srv/repo`` to the ``pacman.conf`` as usual. You can also upload to S3 (``Server = https://s3.eu-central-1.amazonaws.com/repository/aur-clone/x86_64``) or to GitHub (``Server = https://github.com/ahriman/repository/releases/download/aur-clone-x86_64``).
How to sync to S3
^^^^^^^^^^^^^^^^^
#.
Install dependencies:
.. code-block:: shell
pacman -S python-boto3
#.
Create a bucket (e.g. ``repository``).
#.
Create an user with write access to the bucket:
.. code-block::
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListObjectsInBucket",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::repository"
]
},
{
"Sid": "AllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::repository/*"
]
}
]
}
#.
Create an API key for the user and store it.
#.
Configure the service as following:
.. code-block:: ini
[upload]
target = s3
[s3]
access_key = ...
bucket = repository
region = eu-central-1
secret_key = ...
S3 with SSL
"""""""""""
In order to configure S3 on custom domain with SSL (and some other features, like redirects), the CloudFront should be used.
#. Configure S3 as described above.
#. In bucket properties, enable static website hosting with hosting type "Host a static website".
#. Go to AWS Certificate Manager and create public certificate on your domain. Validate domain as suggested.
#. Go to CloudFront and create distribution. The following settings are required:
* Origin domain choose S3 bucket.
* Tick use website endpoint.
* Disable caching.
* Select issued certificate.
#. Point DNS record to CloudFront address.
How to sync to GitHub releases
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#.
Create a repository.
#.
`Create API key <https://github.com/settings/tokens>`__ with scope ``public_repo``.
#.
Configure the service as following:
.. code-block:: ini
[upload]
target = github
[github]
owner = ahriman
password = ...
repository = repository
username = ahriman

145
docs/faq/web.rst Normal file
View File

@ -0,0 +1,145 @@
Web service
-----------
How to setup web service
^^^^^^^^^^^^^^^^^^^^^^^^
#.
Install dependencies:
.. code-block:: shell
yay -S --asdeps python-aiohttp python-aiohttp-jinja2 python-aiohttp-apispec>=3.0.0 python-aiohttp-cors
#.
Configure service:
.. code-block:: ini
[web]
port = 8080
#.
Start the web service ``systemctl enable --now ahriman-web``.
How to enable basic authorization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#.
Install dependencies 😊:
.. code-block:: shell
yay -S --asdeps python-aiohttp-security python-aiohttp-session python-cryptography
#.
Configure the service to enable authorization:
.. code-block:: ini
[auth]
target = configuration
salt = somerandomstring
The ``${auth:salt}`` parameter is optional, but recommended, and can be set to any (random) string.
#.
In order to provide access for reporting from application instances you can (the recommended way) use unix sockets by the following configuration (note, that it requires ``python-requests-unixsocket2`` package to be installed):
.. code-block:: ini
[web]
unix_socket = /run/ahriman/ahriman-web.sock
This socket path must be available for web service instance and must be available for all application instances (e.g. in case if you are using docker container - see above - you need to make sure that the socket is passed to the root filesystem).
By the way, unix socket variable will be automatically set in case if ``--web-unix-socket`` argument is supplied to the ``service-setup`` subcommand.
Alternatively, you need to create user for the service:
.. code-block:: shell
sudo -u ahriman ahriman user-add -r full api
This command will ask for the password, just type it in stdin; **do not** leave the field blank, user will not be able to authorize, and finally configure the application:
.. code-block:: ini
[status]
username = api
password = pa55w0rd
#.
Create end-user with password:
.. code-block:: shell
sudo -u ahriman ahriman user-add -r full my-first-user
#.
Restart web service ``systemctl restart ahriman-web``.
Using PAM authentication
""""""""""""""""""""""""
There is also ability to allow system users to log in. To do so, the following configuration have to be set:
.. code-block:: ini
[auth]
target = pam
full_access_group = wheel
With this setup, every user (except root) will be able to log in by using system password. If user belongs to the ``wheel`` group, the full access will be automatically granted. It is also possible to manually add, block user or change user rights via usual user management process.
How to enable OAuth authorization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#.
Create OAuth web application, download its ``${auth:client_id}`` and ``${auth:client_secret}``.
#.
Guess what? Install dependencies:
.. code-block:: shell
yay -S --asdeps python-aiohttp-security python-aiohttp-session python-cryptography python-aioauth-client
#.
Configure the service:
.. code-block:: ini
[auth]
target = oauth
client_id = ...
client_secret = ...
[web]
address = https://example.com
Configure ``${auth:oauth_provider}`` and ``${auth:oauth_scopes}`` in case if you would like to use different from Google provider. Scope must grant access to user email. ``${web:address}`` is required to make callback URL available from internet.
#.
If you are not going to use unix socket, you also need to create service user (remember to set ``${auth:salt}`` option before if required):
.. code-block:: shell
sudo -u ahriman ahriman user-add --as-service -r full api
#.
Create end-user:
.. code-block:: shell
sudo -u ahriman ahriman user-add -r full my-first-user
When it will ask for the password leave it blank.
#.
Restart web service ``systemctl restart ahriman-web``.
How to implement own interface
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can write your own interface by using API which is provided by the web service. Full autogenerated API documentation is available at ``http://localhost:8080/api-docs``.

View File

@ -33,7 +33,7 @@ Contents
setup
configuration
command-line
faq
faq/index
migration
architecture
advanced-usage

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,18 +1,15 @@
# Maintainer: Evgeniy Alekseev
pkgname='ahriman'
pkgver=2.13.4
pkgver=2.15.0
pkgrel=1
pkgdesc="ArcH linux ReposItory MANager"
arch=('any')
url="https://github.com/arcan1s/ahriman"
license=('GPL3')
depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-cerberus' 'python-inflection' 'python-passlib' 'python-requests' 'python-srcinfo')
depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-inflection' 'python-passlib' 'python-pyelftools' 'python-requests')
makedepends=('python-build' 'python-flit' 'python-installer' 'python-wheel')
optdepends=('breezy: -bzr packages support'
'darcs: -darcs packages support'
'mercurial: -hg packages support'
'python-aioauth-client: web server with OAuth2 authorization'
optdepends=('python-aioauth-client: web server with OAuth2 authorization'
'python-aiohttp: web server'
'python-aiohttp-apispec>=3.0.0: web server'
'python-aiohttp-cors: web server'
@ -20,12 +17,13 @@ optdepends=('breezy: -bzr packages support'
'python-aiohttp-security: web server with authorization'
'python-aiohttp-session: web server with authorization'
'python-boto3: sync to s3'
'python-cerberus: configuration validator'
'python-cryptography: web server with authorization'
'python-requests-unixsocket: client report to web server by unix socket'
'python-matplotlib: usage statistics chart'
'python-requests-unixsocket2: client report to web server by unix socket'
'python-jinja: html report generation'
'python-systemd: journal support'
'rsync: sync by using rsync'
'subversion: -svn packages support')
'rsync: sync by using rsync')
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgname-$pkgver.tar.gz"
'ahriman.sysusers'
'ahriman.tmpfiles')

View File

@ -1 +1,2 @@
d /var/lib/ahriman 0755 ahriman ahriman
d /var/lib/ahriman 0755 ahriman ahriman
d /run/ahriman 0755 ahriman ahriman

View File

@ -3,10 +3,10 @@
include = ahriman.ini.d
; Relative path to configuration used by logging package.
logging = ahriman.ini.d/logging.ini
; Perform database migrations on the application start. Do not touch this option unless you know what are you doing.
; Perform database migrations on the application start. Do not touch this option unless you know what you are doing.
;apply_migrations = yes
; Path to the application SQLite database.
database = /var/lib/ahriman/ahriman.db
database = ${repository:root}/ahriman.db
[alpm]
; Path to pacman system database cache.
@ -17,12 +17,14 @@ mirror = https://geo.mirror.pkgbuild.com/$repo/os/$arch
repositories = core extra multilib
; Pacman's root directory. In the most cases it must point to the system root.
root = /
; Sync files databases too, which is required by deep dependencies check.
sync_files_database = yes
; Use local packages cache. If this option is enabled, the service will be able to synchronize databases (available
; as additional option for some subcommands). If set to no, databases must be synchronized manually.
use_ahriman_cache = yes
[auth]
; Authentication provider, must be one of disabled, configuration, oauth.
; Authentication provider, must be one of disabled, configuration, pam, oauth.
target = disabled
; Allow read-only endpoint to be called without authentication.
allow_read_only = yes
@ -32,6 +34,8 @@ allow_read_only = yes
; Cookie secret key to be used for cookies encryption. Must be valid 32 bytes URL-safe base64-encoded string.
; If not set, it will be generated automatically.
;cookie_secret_key =
; Name of the secondary group to be used as admin group in the service. Required if pam is used.
;full_access_group = wheel
; Authentication cookie expiration in seconds.
;max_age = 604800
; OAuth2 provider icon for the web interface.
@ -40,18 +44,26 @@ allow_read_only = yes
;oauth_provider = GoogleClient
; Scopes list for OAuth2 provider. Required if oauth is used.
;oauth_scopes = https://www.googleapis.com/auth/userinfo.email
; Allow login as root user (only applicable if PAM is used).
;permit_root_login = no
; Optional password salt.
;salt =
[build]
; List of additional flags passed to archbuild command.
;archbuild_flags =
; Path to build command.
;build_command =
; List of packages to be ignored during automatic updates.
;ignore_packages =
; Include debug packages.
;include_debug_packages = yes
; List of additional flags passed to makechrootpkg command.
;makechrootpkg_flags =
; List of additional flags passed to makepkg command.
makepkg_flags = --nocolor --ignorearch
; List of paths to be used for implicit dependency scan. Regular expressions are supported.
scan_paths = ^usr/lib(?!/cmake).*$
; List of enabled triggers in the order of calls.
triggers = ahriman.core.gitremote.RemotePullTrigger ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger ahriman.core.gitremote.RemotePushTrigger
; List of well-known triggers. Used only for configuration purposes.
@ -77,10 +89,10 @@ target =
; Global switch to enable or disable status reporting.
enabled = yes
; Address of the remote service, e.g.:
; address = http://1.0.0.1:8080
; address = http://127.0.0.1:8080
; In case if unix sockets are used, it might point to the valid socket with encoded path, e.g.:
; address = http+unix://%2Fvar%2Flib%2Fahriman%2Fsocket
;address =
;address = http://${web:host}:${web:port}
; Optional password for authentication (if enabled).
;password =
; Do not log HTTP errors if occurs.
@ -92,24 +104,24 @@ suppress_http_log_errors = yes
[web]
; External address of the web service. Will be used for some features like OAuth. If none set will be generated as
; address = http://web.host:web.port
;address =
; address = http://${web:host}:${web:port}
;address = http://${web:host}:${web:port}
; Enable file upload endpoint used by some triggers.
;enable_archive_upload = no
; Address to bind the server.
host = 127.0.0.1
; Full URL to the repository index page used by templates.
;index_url =
; Max file size in bytes which can be uploaded to the server.
; Max file size in bytes which can be uploaded to the server. Requires ${web:enable_archive_upload} to be enabled.
;max_body_size =
; Port to listen. Must be set, if the web service is enabled.
;port =
; Disable status (e.g. package status, logs, etc) endpoints. Useful for build only modes.
;service_only = no
; Path to directory with static files.
static_path = /usr/share/ahriman/templates/static
static_path = ${templates}/static
; List of directories with templates.
templates = /usr/share/ahriman/templates
templates = ${prefix}/share/ahriman/templates
; Path to unix socket. If none set, unix socket will be disabled.
;unix_socket =
; Allow unix socket to be world readable.
@ -200,14 +212,14 @@ target = console
; Console reporting trigger configuration sample.
[console]
; Trigger type name
; Trigger type name.
;type = console
; Use utf8 symbols in output.
use_utf = yes
; Email reporting trigger configuration sample.
[email]
; Trigger type name
; Trigger type name.
;type = email
; Optional URL to the repository homepage.
;homepage=
@ -223,6 +235,8 @@ use_utf = yes
;port =
; List of emails to receive the reports.
;receivers =
; Optional link to the RSS feed.
;rss_url =
; Sender email.
;sender =
; SMTP server SSL mode, one of ssl, starttls, disabled.
@ -232,13 +246,13 @@ template = email-index.jinja2
; Template name to be used for full packages list generation (same as HTML report).
;template_full =
; List of directories with templates.
templates = /usr/share/ahriman/templates
templates = ${prefix}/share/ahriman/templates
; SMTP user.
;user =
; HTML reporting trigger configuration sample.
[html]
; Trigger type name
; Trigger type name.
;type = html
; Optional URL to the repository homepage.
;homepage=
@ -246,14 +260,16 @@ templates = /usr/share/ahriman/templates
;link_path =
; Output path for the HTML report.
;path =
; Optional link to the RSS feed.
;rss_url =
; Template name to be used.
template = repo-index.jinja2
; List of directories with templates.
templates = /usr/share/ahriman/templates
templates = ${prefix}/share/ahriman/templates
; Remote service callback trigger configuration sample.
[remote-call]
; Trigger type name
; Trigger type name.
;type = remote-call
; Call for AUR packages update.
;aur = no
@ -264,9 +280,26 @@ templates = /usr/share/ahriman/templates
; Wait until remote process will be terminated in seconds.
;wait_timeout = -1
; RSS reporting trigger configuration sample.
[rss]
; Trigger type name.
;type = rss
; Optional URL to the repository homepage.
;homepage=
; Prefix for packages links. Link to a package will be formed as link_path / filename.
;link_path =
; Output path for the RSS report.
;path =
; Optional link to the RSS feed.
;rss_url =
; Template name to be used.
template = rss.jinja2
; List of directories with templates.
templates = ${prefix}/share/ahriman/templates
; Telegram reporting trigger configuration sample.
[telegram]
; Trigger type name
; Trigger type name.
;type = telegram
; Telegram bot API key.
;api_key =
@ -276,12 +309,14 @@ templates = /usr/share/ahriman/templates
;homepage=
; Prefix for packages links. Link to a package will be formed as link_path / filename.
;link_path =
; Optional link to the RSS feed.
;rss_url =
; Template name to be used.
template = telegram-index.jinja2
; Telegram specific template mode, one of MarkdownV2, HTML or Markdown.
;template_type = HTML
; List of directories with templates.
templates = /usr/share/ahriman/templates
templates = ${prefix}/share/ahriman/templates
; HTTP request timeout in seconds.
;timeout = 30
@ -292,7 +327,7 @@ target =
; GitHub upload trigger configuration sample.
[github]
; Trigger type name
; Trigger type name.
;type = github
; GitHub repository owner username.
;owner =
@ -309,14 +344,14 @@ target =
; Remote instance upload trigger configuration sample.
[remote-service]
; Trigger type name
; Trigger type name.
;type = remote-service
; HTTP request timeout in seconds.
;timeout = 30
; rsync upload trigger configuration sample.
[rsync]
; Trigger type name
; Trigger type name.
;type = rsync
; rsync command to run.
command = rsync --archive --compress --partial --delete
@ -326,7 +361,7 @@ command = rsync --archive --compress --partial --delete
; S3 upload trigger configuration sample.
[s3]
; Trigger type name
; Trigger type name.
;type = s3
; AWS services access key.
;access_key =

View File

@ -1,5 +1,5 @@
[loggers]
keys = root,http,stderr,boto3,botocore,nose,s3transfer
keys = root,http,stderr,boto3,botocore,nose,s3transfer,sql
[handlers]
keys = console_handler,journald_handler,syslog_handler
@ -64,3 +64,8 @@ propagate = 0
level = INFO
qualname = s3transfer
propagate = 0
[logger_sql]
level = INFO
qualname = sql
propagate = 0

View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Embed elements Elements via Web Component -->
<script src="https://cdn.jsdelivr.net/npm/@stoplight/elements@7.13.7/web-components.min.js" integrity="sha384-aKMPitODat9Dqj3Mva9Rs9jS5Z3KPSW0sFlAOazuULJMFYhAfmORI5SlH9aWIst8" crossorigin="anonymous" type="application/javascript"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stoplight/elements@7.13.7/styles.min.css" integrity="sha384-wPzTs1aFAoGq9gqp9NAs2YVTkFXcU2d6Bx11aKRFhVw2B7o1bCwaV9pGHTlUfD2+" crossorigin="anonymous" type="text/css">
<script src="https://cdn.jsdelivr.net/npm/@stoplight/elements@7.13.7/web-components.min.js" crossorigin="anonymous" type="application/javascript"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stoplight/elements@7.13.7/styles.min.css" crossorigin="anonymous" type="text/css">
</head>
<body>
@ -15,6 +15,7 @@
apiDescriptionUrl="/api-docs/swagger.json"
router="hash"
layout="sidebar"
logo="/static/logo.svg"
/>
</body>

View File

@ -44,28 +44,28 @@
</button>
<ul class="dropdown-menu">
<li>
<button id="package-add-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-add-modal" hidden>
<button id="package-add-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-add-modal">
<i class="bi bi-plus"></i> add
</button>
</li>
<li>
<button id="package-update-button" class="btn dropdown-item" onclick="packagesUpdate()" hidden>
<button id="package-update-button" class="btn dropdown-item" onclick="packagesUpdate()">
<i class="bi bi-play"></i> update
</button>
</li>
<li>
<button id="package-rebuild-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-rebuild-modal" hidden>
<button id="package-rebuild-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-rebuild-modal">
<i class="bi bi-arrow-clockwise"></i> rebuild
</button>
</li>
<li>
<button id="package-remove-button" class="btn dropdown-item" onclick="packagesRemove()" disabled hidden>
<button id="package-remove-button" class="btn dropdown-item" onclick="packagesRemove()" disabled>
<i class="bi bi-trash"></i> remove
</button>
</li>
</ul>
<button id="key-import-button" type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#key-import-modal" hidden>
<button id="key-import-button" type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#key-import-modal">
<i class="bi bi-key"></i><span class="d-none d-sm-inline"> import key</span>
</button>
{% endif %}

View File

@ -1,8 +1,12 @@
<script>
const alertPlaceholder = $("#alert-placeholder");
const alertPlaceholder = document.getElementById("alert-placeholder");
function createAlert(title, message, clz, action, id) {
id ??= md5(title + message); // MD5 id from the content
if (alertPlaceholder.querySelector(`#alert-${id}`)) return; // check if there are duplicates
function createAlert(title, message, clz, action) {
const wrapper = document.createElement("div");
wrapper.id = `alert-${id}`;
wrapper.classList.add("toast", clz);
wrapper.role = "alert";
wrapper.ariaLive = "assertive";
@ -19,21 +23,21 @@
body.innerText = message;
wrapper.appendChild(body);
alertPlaceholder.append(wrapper);
alertPlaceholder.appendChild(wrapper);
const toast = new bootstrap.Toast(wrapper);
wrapper.addEventListener("hidden.bs.toast", () => {
wrapper.addEventListener("hidden.bs.toast", _ => {
wrapper.remove(); // bootstrap doesn't remove elements
(action || reload)();
});
toast.show();
}
function showFailure(title, description, jqXHR, errorThrown) {
function showFailure(title, description, error) {
let details;
try {
details = $.parseJSON(jqXHR.responseText).error; // execution handler json error response
details = JSON.parse(error.text).error; // execution handler json error response
} catch (_) {
details = errorThrown;
details = error.text ?? error.message ?? error;
}
createAlert(title, description(details), "text-bg-danger");
}

View File

@ -36,58 +36,69 @@
</div>
<script>
const keyImportModal = $("#key-import-modal");
const keyImportForm = $("#key-import-form");
keyImportModal.on("hidden.bs.modal", () => {
keyImportBodyInput.text("");
keyImportForm.trigger("reset");
});
const keyImportModal = document.getElementById("key-import-modal");
const keyImportForm = document.getElementById("key-import-form");
const keyImportBodyInput = $("#key-import-body-input");
const keyImportCopyButton = $("#key-import-copy-button");
const keyImportBodyInput = document.getElementById("key-import-body-input");
const keyImportCopyButton = document.getElementById("key-import-copy-button");
const keyImportFingerprintInput = $("#key-import-fingerprint-input");
const keyImportServerInput = $("#key-import-server-input");
const keyImportFingerprintInput = document.getElementById("key-import-fingerprint-input");
const keyImportServerInput = document.getElementById("key-import-server-input");
async function copyPgpKey() {
const logs = keyImportBodyInput.text();
await copyToClipboard(logs, keyImportCopyButton);
const key = keyImportBodyInput.textContent;
await copyToClipboard(key, keyImportCopyButton);
}
function fetchPgpKey() {
const key = keyImportFingerprintInput.val();
const server = keyImportServerInput.val();
const key = keyImportFingerprintInput.value;
const server = keyImportServerInput.value;
if (key && server) {
$.ajax({
url: "/api/v1/service/pgp",
data: {"key": key, "server": server},
type: "GET",
dataType: "json",
success: response => { keyImportBodyInput.text(response.key); },
});
makeRequest(
"/api/v1/service/pgp",
{
query: {
key: key,
server: server,
},
convert: response => response.json(),
},
data => { keyImportBodyInput.textContent = data.key; },
);
}
}
function importPgpKey() {
const key = keyImportFingerprintInput.val();
const server = keyImportServerInput.val();
const key = keyImportFingerprintInput.value;
const server = keyImportServerInput.value;
if (key && server) {
$.ajax({
url: "/api/v1/service/pgp",
data: JSON.stringify({key: key, server: server}),
type: "POST",
contentType: "application/json",
success: _ => {
keyImportModal.modal("hide");
makeRequest(
"/api/v1/service/pgp",
{
method: "POST",
json: {
key: key,
server: server,
},
},
_ => {
bootstrap.Modal.getOrCreateInstance(keyImportModal).hide();
showSuccess("Success", `Key ${key} has been imported`);
},
error: (jqXHR, _, errorThrown) => {
error => {
const message = _ => `Could not import key ${key} from ${server}`;
showFailure("Action failed", message, jqXHR, errorThrown);
showFailure("Action failed", message, error);
},
});
);
}
}
ready(_ => {
keyImportModal.addEventListener("hidden.bs.modal", _ => {
keyImportBodyInput.textContent = "";
keyImportForm.reset();
});
});
</script>

View File

@ -34,47 +34,57 @@
</div>
<script>
const loginModal = $("#login-modal");
const loginForm = $("#login-form");
loginModal.on("hidden.bs.modal", () => {
loginForm.trigger("reset");
});
const loginModal = document.getElementById("login-modal");
const loginForm = document.getElementById("login-form");
const loginPasswordInput = $("#login-password");
const loginUsernameInput = $("#login-username");
const showHidePasswordButton = $("#login-show-hide-password-button");
const loginPasswordInput = document.getElementById("login-password");
const loginUsernameInput = document.getElementById("login-username");
const showHidePasswordButton = document.getElementById("login-show-hide-password-button");
function login() {
const password = loginPasswordInput.val();
const username = loginUsernameInput.val();
const password = loginPasswordInput.value;
const username = loginUsernameInput.value;
if (username && password) {
$.ajax({
url: "/api/v1/login",
data: JSON.stringify({username: username, password: password}),
type: "POST",
contentType: "application/json",
success: _ => {
loginModal.modal("hide");
showSuccess("Logged in", `Successfully logged in as ${username}`, () => location.href = "/");
makeRequest(
"/api/v1/login",
{
method: "POST",
json: {
username: username,
password: password,
},
},
error: (jqXHR, _, errorThrown) => {
const message = _ => `Could not login as ${username}`;
showFailure("Login error", message, jqXHR, errorThrown);
_ => {
bootstrap.Modal.getOrCreateInstance(loginModal).hide();
showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/");
},
});
error => {
const message = _ =>
username === "admin" && password === "admin"
? "You've entered a password for user \"root\", did you make a typo in username?"
: `Could not login as ${username}`;
showFailure("Login error", message, error);
},
);
}
}
function showPassword() {
if (loginPasswordInput.attr("type") === "password") {
loginPasswordInput.attr("type", "text");
showHidePasswordButton.removeClass("bi-eye");
showHidePasswordButton.addClass("bi-eye-slash");
if (loginPasswordInput.getAttribute("type") === "password") {
loginPasswordInput.setAttribute("type", "text");
showHidePasswordButton.classList.remove("bi-eye");
showHidePasswordButton.classList.add("bi-eye-slash");
} else {
loginPasswordInput.attr("type", "password");
showHidePasswordButton.removeClass("bi-eye-slash");
showHidePasswordButton.addClass("bi-eye");
loginPasswordInput.setAttribute("type", "password");
showHidePasswordButton.classList.remove("bi-eye-slash");
showHidePasswordButton.classList.add("bi-eye");
}
}
ready(_ => {
loginModal.addEventListener("hidden.bs.modal", _ => {
loginForm.reset();
});
});
</script>

View File

@ -41,45 +41,14 @@
</div>
<script>
const packageAddModal = $("#package-add-modal");
const packageAddForm = $("#package-add-form");
packageAddModal.on("shown.bs.modal", () => {
$(`#package-add-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true);
});
packageAddModal.on("hidden.bs.modal", () => {
packageAddVariablesDiv.empty();
packageAddForm.trigger("reset");
});
const packageAddModal = document.getElementById("package-add-modal");
const packageAddForm = document.getElementById("package-add-form");
const packageAddInput = $("#package-add-input");
const packageAddRepositoryInput = $("#package-add-repository-input");
const packageAddKnownPackagesList = $("#package-add-known-packages-dlist");
packageAddInput.keyup(() => {
clearTimeout(packageAddInput.data("timeout"));
packageAddInput.data("timeout", setTimeout($.proxy(() => {
const value = packageAddInput.val();
const packageAddInput = document.getElementById("package-add-input");
const packageAddRepositoryInput = document.getElementById("package-add-repository-input");
const packageAddKnownPackagesList = document.getElementById("package-add-known-packages-dlist");
if (value.length >= 3) {
$.ajax({
url: "/api/v1/service/search",
data: {"for": value},
type: "GET",
dataType: "json",
success: response => {
const options = response.map(pkg => {
const option = document.createElement("option");
option.value = pkg.package;
option.innerText = `${pkg.package} (${pkg.description})`;
return option;
});
packageAddKnownPackagesList.empty().append(options);
},
});
}
}, this), 500));
});
const packageAddVariablesDiv = $("#package-add-variables-div");
const packageAddVariablesDiv = document.getElementById("package-add-variables-div");
function packageAddVariableInputCreate() {
const variableInput = document.createElement("div");
@ -109,7 +78,7 @@
variableButtonRemove.classList.add("btn");
variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>";
variableButtonRemove.onclick = _ => { return variableInput.remove(); };
variableButtonRemove.onclick = _ => { variableInput.remove(); };
// bring them together
variableInput.appendChild(variableNameInput);
@ -117,27 +86,26 @@
variableInput.appendChild(variableValueInput);
variableInput.appendChild(variableButtonRemove);
packageAddVariablesDiv.append(variableInput);
packageAddVariablesDiv.appendChild(variableInput);
}
function patchesParse() {
const patches = packageAddVariablesDiv.find(".package-add-variable").map((_, element) => {
const richElement = $(element);
const patches = Array.from(packageAddVariablesDiv.getElementsByClassName("package-add-variable")).map(element => {
return {
key: richElement.find(".package-add-variable-name").val(),
value: richElement.find(".package-add-variable-value").val(),
key: element.querySelector(".package-add-variable-name").value,
value: element.querySelector(".package-add-variable-value").value,
};
}).filter((_, patch) => patch.key).get();
}).filter(patch => patch.key);
return {patches: patches};
}
function packagesAdd(packages, patches, repository) {
packages = packages ?? packageAddInput.val();
packages = packages ?? packageAddInput.value;
patches = patches ?? patchesParse();
repository = repository ?? getRepositorySelector(packageAddRepositoryInput);
if (packages) {
packageAddModal.modal("hide");
bootstrap.Modal.getOrCreateInstance(packageAddModal).hide();
const onSuccess = update => `Packages ${update} have been added`;
const onFailure = error => `Package addition failed: ${error}`;
doPackageAction("/api/v1/service/add", [packages], repository, onSuccess, onFailure, patches);
@ -145,15 +113,54 @@
}
function packagesRequest(packages, patches) {
packages = packages ?? packageAddInput.val();
packages = packages ?? packageAddInput.value;
patches = patches ?? patchesParse();
const repository = getRepositorySelector(packageAddRepositoryInput);
if (packages) {
packageAddModal.modal("hide");
bootstrap.Modal.getOrCreateInstance(packageAddModal).hide();
const onSuccess = update => `Packages ${update} have been requested`;
const onFailure = error => `Package request failed: ${error}`;
doPackageAction("/api/v1/service/request", [packages], repository, onSuccess, onFailure, patches);
}
}
ready(_ => {
packageAddModal.addEventListener("shown.bs.modal", _ => {
const option = packageAddRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`);
option.selected = "selected";
});
packageAddModal.addEventListener("hidden.bs.modal", _ => {
packageAddVariablesDiv.replaceChildren();
packageAddForm.reset();
});
packageAddInput.addEventListener("keyup", _ => {
clearTimeout(packageAddInput.requestTimeout);
packageAddInput.requestTimeout = setTimeout(_ => {
const value = packageAddInput.value;
if (value.length >= 3) {
makeRequest(
"/api/v1/service/search",
{
query: {
for: value,
},
convert: response => response.json(),
},
data => {
const options = data.map(pkg => {
const option = document.createElement("option");
option.value = pkg.package;
option.innerText = `${pkg.package} (${pkg.description})`;
return option;
});
packageAddKnownPackagesList.replaceChildren(...options);
},
);
}
}, 500);
});
});
</script>

View File

@ -45,8 +45,9 @@
<nav>
<div class="nav nav-tabs" role="tablist">
<button id="package-info-logs-button" class="nav-link active" data-bs-toggle="tab" data-bs-target="#package-info-logs" type="button" role="tab" aria-controls="package-info-logs" aria-selected="true"><h3>Build logs</h3></button>
<button id="package-info-changes-button" class="nav-link" data-bs-toggle="tab" data-bs-target="#package-info-changes" type="button" role="tab" aria-controls="package-info-changes" aria-selected="false"><h3>Changes</h3></button>
<button id="package-info-logs-button" class="nav-link active" data-bs-toggle="tab" data-bs-target="#package-info-logs" type="button" role="tab" aria-controls="package-info-logs" aria-selected="true">Build logs</button>
<button id="package-info-changes-button" class="nav-link" data-bs-toggle="tab" data-bs-target="#package-info-changes" type="button" role="tab" aria-controls="package-info-changes" aria-selected="false">Changes</button>
<button id="package-info-events-button" class="nav-link" data-bs-toggle="tab" data-bs-target="#package-info-events" type="button" role="tab" aria-controls="package-info-events" aria-selected="false">Events</button>
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
@ -56,11 +57,30 @@
<div id="package-info-changes" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-changes-button" tabindex="0">
<pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div>
<div id="package-info-events" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-events-button" tabindex="0">
<canvas id="package-info-events-update-chart" hidden></canvas>
<table id="package-info-events-table"
data-classes="table table-hover"
data-sortable="true"
data-sort-name="timestamp"
data-sort-order="desc"
data-toggle="table">
<thead class="table-primary">
<tr>
<th data-align="right" data-field="timestamp">date</th>
<th data-field="event">event</th>
<th data-field="message">description</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()" data-bs-dismiss="modal" hidden><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button>
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal" hidden><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button>
{% if not auth.enabled or auth.username is not none %}
<button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()" data-bs-dismiss="modal"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button>
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal"><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button>
{% endif %}
<button type="button" class="btn btn-secondary" onclick="showPackageInfo()"><i class="bi bi-arrow-clockwise"></i><span class="d-none d-sm-inline"> reload</span></button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button>
</div>
@ -69,61 +89,54 @@
</div>
<script>
const packageInfoModal = $("#package-info-modal");
const packageInfoModalHeader = $("#package-info-modal-header");
const packageInfo = $("#package-info");
packageInfoModal.on("hidden.bs.modal", () => {
packageInfoAurUrl.empty();
packageInfoDepends.empty();
packageInfoGroups.empty();
packageInfoLicenses.empty();
packageInfoPackager.empty();
packageInfoPackages.empty();
packageInfoUpstreamUrl.empty();
packageInfoVersion.empty();
const packageInfoModal = document.getElementById("package-info-modal");
const packageInfoModalHeader = document.getElementById("package-info-modal-header");
const packageInfo = document.getElementById("package-info");
packageInfoVariablesBlock.attr("hidden", true);
packageInfoVariablesDiv.empty();
const packageInfoLogsInput = document.getElementById("package-info-logs-input");
const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button");
packageInfoLogsInput.empty();
packageInfoChangesInput.empty();
const packageInfoChangesInput = document.getElementById("package-info-changes-input");
const packageInfoChangesCopyButton = document.getElementById("package-info-changes-copy-button");
packageInfoModal.trigger("reset");
// so far bootstrap-table only operates with jquery elements
const packageInfoEventsTable = $(document.getElementById("package-info-events-table"));
const packageInfoEventsUpdateChartCanvas = document.getElementById("package-info-events-update-chart");
let packageInfoEventsUpdateChart = null;
hideInfoControls(true);
});
const packageInfoAurUrl = document.getElementById("package-info-aur-url");
const packageInfoDepends = document.getElementById("package-info-depends");
const packageInfoGroups = document.getElementById("package-info-groups");
const packageInfoLicenses = document.getElementById("package-info-licenses");
const packageInfoPackager = document.getElementById("package-info-packager");
const packageInfoPackages = document.getElementById("package-info-packages");
const packageInfoUpstreamUrl = document.getElementById("package-info-upstream-url");
const packageInfoVersion = document.getElementById("package-info-version");
const packageInfoLogsInput = $("#package-info-logs-input");
const packageInfoLogsCopyButton = $("#package-info-logs-copy-button");
const packageInfoVariablesBlock = document.getElementById("package-info-variables-block");
const packageInfoVariablesDiv = document.getElementById("package-info-variables-div");
const packageInfoChangesInput = $("#package-info-changes-input");
const packageInfoChangesCopyButton = $("#package-info-changes-copy-button");
const packageInfoAurUrl = $("#package-info-aur-url");
const packageInfoDepends = $("#package-info-depends");
const packageInfoGroups = $("#package-info-groups");
const packageInfoLicenses = $("#package-info-licenses");
const packageInfoPackager = $("#package-info-packager");
const packageInfoPackages = $("#package-info-packages");
const packageInfoUpstreamUrl = $("#package-info-upstream-url");
const packageInfoVersion = $("#package-info-version");
const packageInfoVariablesBlock = $("#package-info-variables-block");
const packageInfoVariablesDiv = $("#package-info-variables-div");
function clearChart() {
packageInfoEventsUpdateChartCanvas.hidden = true;
if (packageInfoEventsUpdateChart) {
packageInfoEventsUpdateChart.data = {};
packageInfoEventsUpdateChart.update();
}
}
async function copyChanges() {
const changes = packageInfoChangesInput.text();
const changes = packageInfoChangesInput.textContent;
await copyToClipboard(changes, packageInfoChangesCopyButton);
}
async function copyLogs() {
const logs = packageInfoLogsInput.text();
const logs = packageInfoLogsInput.textContent;
await copyToClipboard(logs, packageInfoLogsCopyButton);
}
function hideInfoControls(hidden) {
packageInfoRemoveButton.attr("hidden", hidden);
packageInfoUpdateButton.attr("hidden", hidden);
function highlight(element) {
delete element.dataset.highlighted;
hljs.highlightElement(element);
}
function insertVariable(packageBase, variable) {
@ -150,12 +163,13 @@
variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>";
variableButtonRemove.onclick = _ => {
$.ajax({
url: `/api/v1/packages/${packageBase}/patches/${variable.key}`,
type: "DELETE",
dataType: "json",
success: _ => variableInput.remove(),
});
makeRequest(
`/api/v1/packages/${packageBase}/patches/${variable.key}`,
{
method: "DELETE",
},
_ => variableInput.remove(),
);
};
// bring them together
@ -164,45 +178,93 @@
variableInput.appendChild(variableValueInput);
variableInput.appendChild(variableButtonRemove);
packageInfoVariablesDiv.append(variableInput);
packageInfoVariablesDiv.appendChild(variableInput);
}
function loadChanges(packageBase, onFailure) {
$.ajax({
url: `/api/v1/packages/${packageBase}/changes`,
data: {
architecture: repository.architecture,
repository: repository.repository,
makeRequest(
`/api/v1/packages/${packageBase}/changes`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
type: "GET",
dataType: "json",
success: response => {
const changes = response.changes;
packageInfoChangesInput.text(changes || "");
packageInfoChangesInput.map((_, el) => hljs.highlightElement(el));
data => {
const changes = data.changes;
packageInfoChangesInput.textContent = changes ?? "";
highlight(packageInfoChangesInput);
},
error: onFailure,
});
onFailure,
);
}
function loadEvents(packageBase, onFailure) {
packageInfoEventsTable.bootstrapTable("showLoading");
clearChart();
makeRequest(
"/api/v1/events",
{
query: {
architecture: repository.architecture,
repository: repository.repository,
object_id: packageBase,
limit: 30,
},
convert: response => response.json(),
},
data => {
const events = data.map(event => {
return {
timestamp: new Date(1000 * event.created).toISOStringShort(),
event: event.event,
message: event.message || "",
};
});
const chart = data.filter(event => event.event === "package-updated");
packageInfoEventsTable.bootstrapTable("load", events);
packageInfoEventsTable.bootstrapTable("hideLoading");
if (packageInfoEventsUpdateChart) {
packageInfoEventsUpdateChart.config.data = {
labels: chart.map(event => new Date(1000 * event.created).toISOStringShort()),
datasets: [{
label: "update duration, s",
data: chart.map(event => event.data.took),
cubicInterpolationMode: "monotone",
tension: 0.4,
}],
};
packageInfoEventsUpdateChart.update();
}
packageInfoEventsUpdateChartCanvas.hidden = !chart.length;
},
onFailure,
);
}
function loadLogs(packageBase, onFailure) {
$.ajax({
url: `/api/v2/packages/${packageBase}/logs`,
data: {
architecture: repository.architecture,
repository: repository.repository,
makeRequest(
`/api/v2/packages/${packageBase}/logs`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
type: "GET",
dataType: "json",
success: response => {
const logs = response.map(log_record => {
data => {
const logs = data.map(log_record => {
return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`;
});
packageInfoLogsInput.text(logs.join("\n"));
packageInfoLogsInput.map((_, el) => hljs.highlightElement(el));
packageInfoLogsInput.textContent = logs.join("\n");
highlight(packageInfoLogsInput);
},
error: onFailure,
});
onFailure,
);
}
function loadPackage(packageBase, onFailure) {
@ -214,16 +276,17 @@
return ["bg-secondary", "text-white"];
};
$.ajax({
url: `/api/v1/packages/${packageBase}`,
data: {
architecture: repository.architecture,
repository: repository.repository,
makeRequest(
`/api/v1/packages/${packageBase}`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
type: "GET",
dataType: "json",
success: response => {
const description = response.find(Boolean);
data => {
const description = data.find(Boolean);
const packages = Object.keys(description.package.packages);
const aurUrl = description.package.remote.web_url;
const upstreamUrls = Array.from(
@ -233,80 +296,111 @@
)
).sort();
packageInfo.text(`${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`);
packageInfo.textContent = `${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`;
packageInfoModalHeader.removeClass();
packageInfoModalHeader.addClass("modal-header");
headerClass(description.status.status).forEach(clz => packageInfoModalHeader.addClass(clz));
packageInfoModalHeader.classList.remove(...packageInfoModalHeader.classList);
packageInfoModalHeader.classList.add("modal-header");
headerClass(description.status.status).forEach(clz => packageInfoModalHeader.classList.add(clz));
packageInfoAurUrl.html(aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : "");
packageInfoDepends.html(listToTable(
packageInfoAurUrl.innerHTML = aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : "";
packageInfoDepends.innerHTML = listToTable(
Object.values(description.package.packages)
.reduce((accumulator, currentValue) => {
return accumulator.concat(currentValue.depends.filter(v => packages.indexOf(v) === -1))
.concat(currentValue.make_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (make)`))
.concat(currentValue.opt_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (optional)`));
}, [])
));
packageInfoGroups.html(listToTable(extractListProperties(description.package, "groups")));
packageInfoLicenses.html(listToTable(extractListProperties(description.package, "licenses")));
packageInfoPackager.text(description.package.packager);
packageInfoPackages.html(listToTable(packages));
packageInfoUpstreamUrl.html(upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>"));
packageInfoVersion.text(description.package.version);
hideInfoControls(false);
);
packageInfoGroups.innerHTML = listToTable(extractListProperties(description.package, "groups"));
packageInfoLicenses.innerHTML = listToTable(extractListProperties(description.package, "licenses"));
packageInfoPackager.textContent = description.package.packager;
packageInfoPackages.innerHTML = listToTable(packages);
packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>");
packageInfoVersion.textContent = description.package.version;
},
error: (jqXHR, _, errorThrown) => {
hideInfoControls(true);
onFailure(jqXHR, null, errorThrown);
},
});
onFailure,
);
}
function loadPatches(packageBase, onFailure) {
$.ajax({
url: `/api/v1/packages/${packageBase}/patches`,
type: "GET",
dataType: "json",
success: response => {
packageInfoVariablesDiv.empty();
response.map(patch => insertVariable(packageBase, patch));
packageInfoVariablesBlock.attr("hidden", response.length === 0);
makeRequest(
`/api/v1/packages/${packageBase}/patches`,
{
convert: response => response.json(),
},
error: onFailure,
});
data => {
packageInfoVariablesDiv.replaceChildren();
data.map(patch => insertVariable(packageBase, patch));
packageInfoVariablesBlock.hidden = !data.length;
},
onFailure,
);
}
function packageInfoRemove() {
const packageBase = packageInfoModal.data("package");
if (packageBase) return packagesRemove([packageBase]);
const packageBase = packageInfoModal.package;
packagesRemove([packageBase]);
}
function packageInfoUpdate() {
const packageBase = packageInfoModal.data("package");
if (packageBase) return packagesAdd(packageBase, [], repository);
const packageBase = packageInfoModal.package;
packagesAdd(packageBase, [], repository);
}
function showPackageInfo(packageBase) {
const isPackageBaseSet = packageBase !== undefined;
if (isPackageBaseSet)
packageInfoModal.data("package", packageBase); // set package base as currently used
else
packageBase = packageInfoModal.data("package"); // read package base from the current window attribute
if (isPackageBaseSet) {
// set package base as currently used
packageInfoModal.package = packageBase;
} else {
// read package base from the current window attribute
packageBase = packageInfoModal.package;
}
const onFailure = (jqXHR, _, errorThrown) => {
const onFailure = error => {
if (isPackageBaseSet) {
const message = error => `Could not load package ${packageBase} info: ${error}`;
showFailure("Load failure", message, jqXHR, errorThrown);
const message = details => `Could not load package ${packageBase} info: ${details}`;
showFailure("Load failure", message, error);
}
};
loadPackage(packageBase, onFailure);
loadPatches(packageBase, onFailure);
loadLogs(packageBase, onFailure);
loadChanges(packageBase, onFailure)
loadChanges(packageBase, onFailure);
loadEvents(packageBase, onFailure);
if (isPackageBaseSet) packageInfoModal.modal("show");
if (isPackageBaseSet) {
bootstrap.Modal.getOrCreateInstance(packageInfoModal).show();
}
}
ready(_ => {
packageInfoEventsUpdateChart = new Chart(packageInfoEventsUpdateChartCanvas, {
type: "line",
data: {},
options: {
responsive: true,
},
});
packageInfoModal.addEventListener("hidden.bs.modal", _ => {
packageInfoAurUrl.textContent = "";
packageInfoDepends.textContent = "";
packageInfoGroups.textContent = "";
packageInfoLicenses.textContent = "";
packageInfoPackager.textContent = "";
packageInfoPackages.textContent = "";
packageInfoUpstreamUrl.textContent = "";
packageInfoVersion.textContent = "";
packageInfoVariablesBlock.hidden = true;
packageInfoVariablesDiv.replaceChildren();
packageInfoLogsInput.textContent = "";
packageInfoChangesInput.textContent = "";
packageInfoEventsTable.bootstrapTable("load", []);
clearChart();
});
});
</script>

View File

@ -33,25 +33,31 @@
</div>
<script>
const packageRebuildModal = $("#package-rebuild-modal");
const packageRebuildForm = $("#package-rebuild-form");
packageRebuildModal.on("shown.bs.modal", () => {
$(`#package-rebuild-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true);
const packageRebuildModal = document.getElementById("package-rebuild-modal");
const packageRebuildForm = document.getElementById("package-rebuild-form");
});
packageRebuildModal.on("hidden.bs.modal", () => { packageRebuildForm.trigger("reset"); });
const packageRebuildDependencyInput = $("#package-rebuild-dependency-input");
const packageRebuildRepositoryInput = $("#package-rebuild-repository-input");
const packageRebuildDependencyInput = document.getElementById("package-rebuild-dependency-input");
const packageRebuildRepositoryInput = document.getElementById("package-rebuild-repository-input");
function packagesRebuild() {
const packages = packageRebuildDependencyInput.val();
const packages = packageRebuildDependencyInput.value;
const repository = getRepositorySelector(packageRebuildRepositoryInput);
if (packages) {
packageRebuildModal.modal("hide");
bootstrap.Modal.getOrCreateInstance(packageRebuildModal).hide();
const onSuccess = update => `Repository rebuild has been run for packages which depend on ${update}`;
const onFailure = error => `Repository rebuild failed: ${error}`;
doPackageAction("/api/v1/service/rebuild", [packages], repository, onSuccess, onFailure);
}
}
ready(_ => {
packageRebuildModal.addEventListener("shown.bs.modal", _ => {
const option = packageRebuildRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`);
option.selected = "selected";
});
packageRebuildModal.addEventListener("hidden.bs.modal", _ => {
packageRebuildForm.reset();
});
});
</script>

View File

@ -1,77 +1,34 @@
<script>
const keyImportButton = $("#key-import-button");
const packageAddButton = $("#package-add-button");
const packageRebuildButton = $("#package-rebuild-button");
const packageRemoveButton = $("#package-remove-button");
const packageUpdateButton = $("#package-update-button");
const packageInfoRemoveButton = $("#package-info-remove-button");
const packageInfoUpdateButton = $("#package-info-update-button");
const packageRemoveButton = document.getElementById("package-remove-button");
const packageUpdateButton = document.getElementById("package-update-button");
let repository = null;
$("#repositories a").on("click", (event) => {
const element = event.target;
repository = {
architecture: element.dataset.architecture,
repository: element.dataset.repository,
};
packageUpdateButton.html(`<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`);
$(`#${element.id}`).tab("show");
reload();
});
const table = $("#packages");
table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", () => {
packageRemoveButton.prop("disabled", !table.bootstrapTable("getSelections").length);
});
table.on("click-row.bs.table", (self, data, row, cell) => {
if (0 === cell || "base" === cell) {
const method = data[0] === true ? "uncheckBy" : "checkBy"; // fck javascript
table.bootstrapTable(method, {field: "id", values: [data.id]});
} else showPackageInfo(data.id);
});
table.on("created-controls.bs.table", () => {
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
pickerInput.daterangepicker({
autoUpdateInput: false,
locale: {
cancelLabel: "Clear",
},
});
// so far bootstrap-table only operates with jquery elements
const table = $(document.getElementById("packages"));
pickerInput.on("apply.daterangepicker", (event, picker) => {
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
table.bootstrapTable("triggerSearch");
});
pickerInput.on("cancel.daterangepicker", () => {
pickerInput.val("");
table.bootstrapTable("triggerSearch");
});
});
const statusBadge = $("#badge-status");
const versionBadge = $("#badge-version");
const statusBadge = document.getElementById("badge-status");
const versionBadge = document.getElementById("badge-version");
function doPackageAction(uri, packages, repository, successText, failureText, data) {
const queryParams = $.param({
architecture: repository.architecture,
repository: repository.repository,
}); // it will never be empty btw
$.ajax({
url: `${uri}?${queryParams}`,
data: JSON.stringify(Object.assign({}, {packages: packages}, data || {})),
type: "POST",
contentType: "application/json",
success: _ => {
makeRequest(
uri,
{
method: "POST",
query: {
architecture: repository.architecture,
repository: repository.repository,
},
json: Object.assign({}, {packages: packages}, data || {}),
},
_ => {
const message = successText(packages.join(", "));
showSuccess("Success", message);
},
error: (jqXHR, _, errorThrown) => {
showFailure("Action failed", failureText, jqXHR, errorThrown);
error => {
showFailure("Action failed", failureText, error);
},
});
);
}
function filterListGroups() {
@ -87,10 +44,10 @@
}
function getRepositorySelector(selector) {
const selected = selector.find(":selected");
const selected = selector.options[selector.selectedIndex];
return {
architecture: selected.data("architecture"),
repository: selected.data("repository"),
architecture: selected.getAttribute("data-architecture"),
repository: selected.getAttribute("data-repository"),
};
}
@ -98,14 +55,6 @@
return table.bootstrapTable("getSelections").map(row => row.id);
}
function hideControls(hidden) {
keyImportButton.attr("hidden", hidden);
packageAddButton.attr("hidden", hidden);
packageRebuildButton.attr("hidden", hidden);
packageRemoveButton.attr("hidden", hidden);
packageUpdateButton.attr("hidden", hidden);
}
function packagesRemove(packages) {
packages = packages ?? getSelection();
const onSuccess = update => `Packages ${update} have been removed`;
@ -135,16 +84,17 @@
return "btn-outline-secondary";
};
$.ajax({
url: "/api/v1/packages",
data: {
architecture: repository.architecture,
repository: repository.repository,
makeRequest(
"/api/v1/packages",
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
type: "GET",
dataType: "json",
success: response => {
const payload = response.map(description => {
data => {
const payload = data.map(description => {
const package_base = description.package.base;
const web_url = description.package.remote.web_url;
return {
@ -163,10 +113,9 @@
table.bootstrapTable("load", payload);
table.bootstrapTable("uncheckAll");
table.bootstrapTable("hideLoading");
hideControls(false);
},
error: (jqXHR, _, errorThrown) => {
if ((jqXHR.status === 401) || (jqXHR.status === 403)) {
error => {
if ((error.status === 401) || (error.status === 403)) {
// authorization error
const text = "In order to see statuses you must login first.";
table.find("tr.unauthorized").remove();
@ -174,39 +123,39 @@
table.bootstrapTable("hideLoading");
} else {
// other errors
const message = error => `Could not load list of packages: ${error}`;
showFailure("Load failure", message, jqXHR, errorThrown);
const message = details => `Could not load list of packages: ${details}`;
showFailure("Load failure", message, error);
}
hideControls(true);
},
});
);
$.ajax({
url: "/api/v1/status",
data: {
architecture: repository.architecture,
repository: repository.repository,
makeRequest(
"/api/v1/status",
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
type: "GET",
dataType: "json",
success: response => {
versionBadge.html(`<i class="bi bi-github"></i> ahriman ${safe(response.version)}`);
data => {
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
statusBadge
.popover("dispose")
.attr("data-bs-content", `${response.status.status} at ${new Date(1000 * response.status.timestamp).toISOStringShort()}`)
.popover();
statusBadge.removeClass();
statusBadge.addClass("btn");
statusBadge.addClass(badgeClass(response.status.status));
statusBadge.classList.remove(...statusBadge.classList);
statusBadge.classList.add("btn");
statusBadge.classList.add(badgeClass(data.status.status));
const popover = bootstrap.Popover.getOrCreateInstance(statusBadge);
popover.dispose();
statusBadge.dataset.bsContent = `${data.status.status} at ${new Date(1000 * data.status.timestamp).toISOStringShort()}`;
bootstrap.Popover.getOrCreateInstance(statusBadge);
},
});
);
}
function selectRepository() {
const fragment = window.location.hash.replace("#", "") || "{{ repositories[0].id }}";
const element = $(`#${fragment}-link`);
element.click();
document.getElementById(`${fragment}-link`).click();
}
function statusFormat(value) {
@ -220,9 +169,65 @@
return {classes: cellClass(value)};
}
$(() => {
table.bootstrapTable({});
statusBadge.popover();
ready(_ => {
document.querySelectorAll("#repositories a").forEach(element => {
element.onclick = _ => {
repository = {
architecture: element.dataset.architecture,
repository: element.dataset.repository,
};
if (packageUpdateButton) {
packageUpdateButton.innerHTML = `<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`;
}
bootstrap.Tab.getOrCreateInstance(document.getElementById(element.id)).show();
reload();
};
});
table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", _ => {
if (packageRemoveButton) {
packageRemoveButton.disabled = !table.bootstrapTable("getSelections").length;
}
});
table.on("click-row.bs.table", (self, data, row, cell) => {
if (0 === cell || "base" === cell) {
const method = data[0] === true ? "uncheckBy" : "checkBy"; // fck javascript
table.bootstrapTable(method, {field: "id", values: [data.id]});
} else showPackageInfo(data.id);
});
table.on("created-controls.bs.table", _ => {
new easepick.create({
element: document.querySelector(".bootstrap-table-filter-control-timestamp"),
css: [
"https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",
],
grid: 2,
calendars: 2,
autoApply: false,
locale: {
cancel: "Clear",
},
RangePlugin: {
tooltip: false,
},
plugins: [
"RangePlugin",
],
setup: picker => {
picker.on("select", _ => { table.bootstrapTable("triggerSearch"); });
// replace "Cancel" behaviour to "Clear"
picker.onClickCancelButton = element => {
if (picker.isCancelButton(element)) {
picker.clear();
picker.hide();
table.bootstrapTable("triggerSearch");
}
};
},
});
});
bootstrap.Popover.getOrCreateInstance(statusBadge);
selectRepository();
});
</script>
</script>

View File

@ -7,6 +7,10 @@
{% include "utils/style.jinja2" %}
{% include "user-style.jinja2" ignore missing %}
{% if rss_url is not none %}
<link rel="alternate" href="{{ rss_url }}" type="application/rss+xml">
{% endif %}
</head>
<body>
@ -101,32 +105,13 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
</div>
<script>
const table = $("#packages");
table.on("created-controls.bs.table", () => {
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
pickerInput.daterangepicker({
autoUpdateInput: false,
locale: {
cancelLabel: "Clear",
},
});
const table = $(document.getElementById("packages"));
pickerInput.on("apply.daterangepicker", (event, picker) => {
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
table.bootstrapTable("triggerSearch");
});
pickerInput.on("cancel.daterangepicker", () => {
pickerInput.val("");
table.bootstrapTable("triggerSearch");
});
});
const pacmanConf = $("#pacman-conf");
const pacmanConfCopyButton = $("#copy-btn");
const pacmanConf = document.getElementById("pacman-conf");
const pacmanConfCopyButton = document.getElementById("copy-btn");
async function copyPacmanConf() {
const conf = pacmanConf.text();
const conf = pacmanConf.textContent;
await copyToClipboard(conf, pacmanConfCopyButton);
}
@ -141,6 +126,40 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
function filterListLicenses() {
return extractDataList(table.bootstrapTable("getData"), "licenses");
}
ready(_ => {
table.on("created-controls.bs.table", _ => {
new easepick.create({
element: document.querySelector(".bootstrap-table-filter-control-timestamp"),
css: [
"https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",
],
grid: 2,
calendars: 2,
autoApply: false,
locale: {
cancel: "Clear",
},
RangePlugin: {
tooltip: false,
},
plugins: [
"RangePlugin",
],
setup: picker => {
picker.on("select", _ => { table.bootstrapTable("triggerSearch"); });
// replace "Cancel" behaviour to "Clear"
picker.onClickCancelButton = element => {
if (picker.isCancelButton(element)) {
picker.clear();
picker.hide();
table.bootstrapTable("triggerSearch");
}
};
},
});
});
});
</script>
</body>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ repository }}: Recent package updates</title>
{% if homepage is not none %}
<link>{{ homepage }}</link>
{% endif %}
<description>Recently updated packages in the {{ repository }}.</description>
{% if rss_url is not none %}
<atom:link href="{{ rss_url }}" rel="self"/>
{% endif %}
<language>en-us</language>
<lastBuildDate>{{ last_update }}</lastBuildDate>
{% for package in packages %}
<item>
<title>{{ package.name }} {{ package.version }} {{ package.architecture }}</title>
<link>{{ link_path }}/{{ package.filename }}</link>
<description>{{ package.description }}</description>
<pubDate>{{ package.build_date }}</pubDate>
<guid isPermaLink="false">{{ package.tag }}</guid>
<category>{{ repository }}</category>
<category>{{ package.architecture }}</category>
</item>
{% endfor %}
</channel>
</rss>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 181 KiB

View File

@ -1,70 +1,721 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="256.000000pt" height="256.000000pt" viewBox="0 0 256.000000 256.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1019 2546 c-51 -18 -92 -49 -136 -103 -34 -41 -83 -73 -112 -73 -6
0 4 22 20 49 17 27 30 54 28 59 -7 17 -153 -102 -176 -143 -13 -23 -30 -40
-40 -40 -15 0 -18 9 -18 61 0 49 6 73 33 125 l33 64 -42 -40 c-50 -49 -82 -97
-98 -150 -31 -102 -43 -125 -77 -146 -19 -11 -48 -42 -65 -67 -17 -26 -62 -76
-100 -112 -69 -66 -69 -66 -69 -120 0 -30 5 -62 10 -70 5 -8 10 -10 10 -4 0 7
21 35 46 63 69 77 154 95 154 33 0 -42 -27 -126 -50 -155 l-21 -26 25 -7 c34
-8 63 10 86 56 27 53 74 105 127 142 42 29 44 32 38 68 -6 33 -3 40 22 60 25
20 36 22 96 17 83 -7 121 5 137 43 7 16 19 31 28 34 10 3 -9 3 -40 1 -65 -6
-84 8 -48 37 34 27 118 24 180 -7 57 -29 115 -32 150 -8 l24 17 -24 6 c-14 3
-27 14 -28 24 -4 17 1 18 46 13 58 -7 118 -34 147 -67 38 -44 107 -80 149 -80
36 1 38 2 21 12 -41 23 -115 108 -115 133 0 13 58 -27 94 -64 42 -43 86 -58
133 -46 28 7 28 7 6 18 -13 5 -23 19 -23 29 0 14 6 19 23 16 17 -2 32 -23 62
-85 48 -99 63 -115 123 -141 97 -41 101 -40 50 16 -54 60 -80 113 -76 149 l3
26 58 -47 c61 -50 87 -89 87 -131 0 -43 27 -93 59 -109 38 -20 37 -21 36 11 0
45 24 38 47 -14 19 -41 22 -63 20 -146 -2 -91 0 -103 25 -148 45 -83 54 -83
47 2 -6 74 11 155 32 153 20 -2 47 -101 48 -179 1 -65 -3 -88 -22 -122 -24
-46 -28 -98 -10 -138 14 -30 24 -32 31 -5 8 30 37 25 37 -6 0 -53 -23 -113
-62 -160 -52 -63 -58 -81 -58 -167 l0 -72 35 65 c40 75 98 135 103 107 4 -19
-37 -114 -69 -158 -11 -16 -49 -46 -85 -66 -64 -37 -94 -76 -94 -122 0 -20 1
-21 24 -6 19 13 25 13 35 2 17 -21 -15 -43 -73 -51 -85 -11 -126 -26 -164 -61
-35 -31 -80 -95 -67 -95 3 0 29 12 57 26 52 26 168 45 168 28 0 -12 -92 -91
-123 -105 -20 -9 -34 -8 -71 6 -52 20 -104 14 -130 -14 -17 -19 -17 -20 6 -23
12 -2 24 -11 26 -20 4 -22 -37 -23 -189 -7 -99 11 -104 10 -151 -12 -26 -13
-48 -27 -48 -30 0 -3 25 -16 55 -28 30 -13 55 -26 55 -31 0 -8 -73 -20 -119
-20 -44 0 -99 20 -130 46 -37 31 -87 46 -124 38 l-27 -6 22 -18 c16 -13 20
-22 12 -29 -18 -19 -125 42 -174 100 -45 53 -95 82 -165 95 l-40 7 52 -41 c96
-76 114 -128 31 -86 -105 52 -120 69 -147 172 -9 31 -21 48 -44 62 -41 25 -61
26 -49 2 5 -9 7 -23 5 -29 -10 -27 -32 -11 -57 39 -21 43 -26 66 -26 132 0 71
-4 87 -29 131 -32 55 -80 106 -67 71 21 -58 18 -206 -4 -206 -5 0 -30 43 -56
95 l-48 96 17 47 c21 57 21 89 2 122 -14 25 -14 25 -15 3 0 -14 -6 -23 -16
-23 -14 0 -16 8 -10 53 4 28 18 70 31 92 14 22 31 55 40 73 18 37 32 152 19
152 -5 0 -17 -21 -28 -46 -18 -45 -61 -104 -75 -104 -4 0 -4 32 0 72 6 55 16
83 40 122 24 37 34 66 37 108 6 75 -1 91 -22 51 -16 -32 -48 -44 -61 -23 -8
12 22 69 40 76 19 8 41 43 65 105 l21 52 -29 -29 c-16 -16 -48 -40 -71 -54
-23 -14 -56 -45 -72 -69 -28 -43 -29 -47 -29 -175 0 -186 -12 -220 -43 -122
-10 29 -15 62 -11 72 4 14 -2 11 -20 -9 -31 -33 -33 -65 -7 -115 21 -40 38
-112 27 -112 -16 0 -58 35 -71 59 l-14 26 -1 -37 c0 -24 13 -63 36 -108 39
-76 51 -155 24 -155 -8 0 -20 16 -27 35 l-11 35 -7 -29 c-11 -40 11 -127 43
-175 15 -22 56 -72 90 -111 70 -78 66 -86 -28 -51 -71 27 -60 7 30 -54 71 -48
106 -93 86 -112 -4 -4 -46 12 -93 37 -110 58 -109 58 -87 20 29 -49 70 -81
188 -145 114 -63 148 -94 126 -120 -13 -16 -52 -6 -82 22 -28 25 -21 0 11 -44
45 -63 100 -83 259 -99 154 -15 221 -29 272 -54 l35 -18 -35 -6 c-56 -10 -164
-26 -175 -26 -5 -1 15 -10 45 -21 62 -23 124 -27 255 -15 72 6 94 5 109 -7 28
-21 11 -37 -42 -38 l-47 -1 40 -19 c63 -31 153 -22 244 25 80 41 166 66 224
66 l38 0 -26 -35 c-15 -19 -48 -48 -73 -66 l-47 -31 72 4 c71 4 72 4 130 59
66 64 104 86 160 95 27 4 42 2 50 -8 16 -19 4 -34 -43 -58 l-39 -19 54 -1 c71
0 129 28 181 88 22 26 68 80 102 120 35 41 74 89 87 108 13 19 26 33 28 31 2
-2 -3 -46 -12 -98 -20 -128 -20 -128 26 -73 52 63 64 91 83 196 18 108 39 150
69 146 23 -3 27 -20 14 -70 -11 -42 18 -25 49 28 34 58 41 139 20 222 -21 84
-21 83 19 172 19 43 38 99 41 125 l7 46 38 -68 39 -68 0 88 c0 80 -3 93 -35
157 -41 80 -47 140 -15 140 11 0 26 -12 34 -27 15 -27 15 -27 16 35 0 54 -4
70 -29 105 -16 23 -49 57 -74 76 -56 42 -111 153 -122 248 l-7 63 58 -26 c32
-14 71 -35 86 -45 40 -29 35 -10 -18 60 -34 45 -65 72 -117 103 -118 69 -153
102 -141 132 9 22 25 20 68 -9 42 -28 43 -26 14 26 -36 65 -136 119 -217 119
-48 0 -233 88 -211 100 8 4 44 11 80 14 129 14 130 15 58 47 -62 29 -64 29
-198 23 -121 -6 -138 -5 -153 11 -25 24 -6 43 46 47 l42 3 -35 20 c-25 13 -53
19 -98 19 -54 0 -74 -6 -143 -42 -76 -39 -139 -54 -139 -33 0 6 45 32 100 60
l99 50 -55 7 c-76 9 -111 2 -214 -46 -99 -46 -155 -51 -155 -15 0 14 12 24 44
36 40 14 42 16 20 22 -37 10 -80 8 -120 -7z"/>
</g>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="800"
height="800"
version="1.1"
id="svg106"
sodipodi:docname="logo.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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="namedview106"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.8720703"
inkscape:cx="511.73292"
inkscape:cy="499.71414"
inkscape:window-width="3840"
inkscape:window-height="2160"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg106" />
<path
fill="#132b6d"
d="m 387.66175,2.9352426 c 109.978,-0.5206001 203.504,31.4880054 285.824,108.1504174 159.376,148.42203 165.076,403.05807 17.164,561.4021 -72.884,78.02402 -172.364,120.98802 -278.558,124.58202 -105.508,0.092 -196.612,-29.306 -277.44,-100.25401 C -17.844855,562.95974 -40.874855,327.5097 78.894545,164.89367 155.84375,60.416853 261.60375,10.958044 387.66175,2.9352426 Z"
id="path1"
style="stroke-width:2" />
<defs
id="defs2">
<linearGradient
id="gradient_0"
gradientUnits="userSpaceOnUse"
x1="361.42581"
y1="223.77209"
x2="195.62669"
y2="358.78311"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#C29024"
id="stop1" />
<stop
offset="1"
stop-color="#DCBB57"
id="stop2" />
</linearGradient>
</defs>
<path
fill="url(#gradient_0)"
d="M 351.39175,758.48578 C 168.77575,730.12777 41.748945,587.64375 38.358945,403.44571 34.725145,206.00568 197.09775,42.52665 394.25175,39.316449 c 199.908,-3.255 364.866,156.319231 367.572,354.681261 1.264,13.294 -0.766,28.52001 -2.266,41.84201 -22.772,202.34804 -192.312,343.02406 -397.788,324.19806 -2.656,-0.244 -8.104,-0.266 -10.378,-1.552 z"
id="path2"
style="fill:url(#gradient_0);stroke-width:2" />
<path
fill="#fade6b"
d="m 322.01375,466.26772 c -11.018,-19.004 -31.84,-33.106 -51.826,-41.634 -1.678,-0.714 -7.54,-2.124 -8.182,-3.564 l 0.732,-0.666 c 4,0.842 8.334,3.966 12.02,5.806 6.386,3.184 15.572,2.11 22.174,5.236 4.75,2.248 4.01,8.946 6.388,12.528 4.924,7.418 31.496,22.526 25.196,30.44801 -1.88,2.366 3.59,25.088 -6.502,27.406 9.19,-11.64 6.228,-23.022 0,-35.56001 z"
id="path3"
style="stroke-width:2" />
<path
fill="#f1ead8"
d="m 607.74175,596.82375 c 1.336,0.334 2.464,0.632 3.666,1.342 -20.054,9.052 -64.106,28.032 -86.62,22.686 4.1,-6.492 9.65,-12.676 16.658,-16.064 19.842,0.438 47.962,-0.334 66.296,-7.964 z"
id="path4"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 501.15175,566.49574 c 6.586,7.622 13.706,16.72001 22.154,22.30601 4.128,2.764 8.214,4.434 12.892,6.05 9.566,1.388 23.592,3.746 32.986,1.972 14.562,-1.188 28.228,-3.904 42.224,-8.022 l -1.062,3.132 c -0.626,1.91 -1.408,3.284 -2.604,4.89 -18.334,7.63 -46.454,8.402 -66.296,7.964 -7.008,3.388 -12.558,9.572 -16.658,16.064 -9.11,-5.624 -25.204,-20.256 -33.116,-27.858 -0.438,-2.818 -1.834,-5.878 -2.786,-8.594 3.066,-7.94801 11.252,-13.00801 12.266,-17.90401 z"
id="path5"
style="stroke-width:2" />
<path
fill="#f1ead8"
d="m 279.36575,419.47772 c 17.368,-2.17 52.85,13.874 66.39,23.914 16.654,12.346 42.944,41.42201 46.084,62.86401 l -0.632,0.818 c -7.4,-0.814 -14.928,-3.078 -22.004,0 -15.638,-34.97 -32.316,-54.81001 -66.512,-75.00601 -7.612,-4.496 -15.806,-7.926 -23.326,-12.59 z"
id="path6"
style="stroke-width:2" />
<path
fill="#f2e8a9"
d="m 358.50775,559.66374 c 12.018,13.204 20.532,31.28401 42.394,32.76001 26.828,1.808 75.452,-16.66001 100.25,-25.92801 -1.014,4.896 -9.2,9.956 -12.266,17.90401 0.952,2.716 2.348,5.776 2.786,8.594 -23.926,3.644 -42.772,14.97 -73.036,18.024 -31.48,3.176 -57.178,-20.208 -60.128,-51.35401 z"
id="path7"
style="stroke-width:2" />
<defs
id="defs8">
<linearGradient
id="gradient_1"
gradientUnits="userSpaceOnUse"
x1="251.38866"
y1="364.7413"
x2="250.98038"
y2="386.04666"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#8B5E10"
id="stop7" />
<stop
offset="1"
stop-color="#CF9A22"
id="stop8" />
</linearGradient>
</defs>
<path
fill="url(#gradient_1)"
d="m 310.19775,643.62576 c 2.576,-42.33201 43.824,-23.71801 68.946,-13.31801 29.856,12.36001 44.646,14.27401 76.866,17.40001 6.062,0.588 19.738,0.234 24.164,5.272 -4.906,4.506 -30.934,9.33 -37.886,8.6 -14.06,-1.944 -28.422,0.378 -42.516,0.02 -15.588,-0.394 -24.788,-3.174 -41.264,-0.02 -10.692,-0.35 -39.162,-6.928 -48.31,-12.01 l -0.164,-0.692 c -4.454,-4.498 -8.004,-10.198 -11.632,-15.38 h 1.106 c 3.348,3.464 6.672,7.448 10.69,10.128 z"
id="path8"
style="fill:url(#gradient_1);stroke-width:2" />
<path
fill="#e4c267"
d="m 533.18975,212.81168 3.008,1.8 c 104.752,81.45401 120.284,223.88804 39.258,327.17806 -4.874,6.214 -10.864,11.518 -15.55,17.874 -13.234,7.248 -22.01,22.26601 -36.562,27.66201 -3.272,-0.346 -14.796,-14.16001 -18.132,-17.28801 9.246,-9.45 22.016,-16.352 32.638,-26.984 75.99,-76.05602 84.014,-197.54404 14.068,-280.22005 -6.722,-7.946 -14.4,-14.688 -21.786,-21.97401 2.61,-8.98 1.014,-18.91 3.058,-28.048 z"
id="path9"
style="stroke-width:2" />
<defs
id="defs10">
<linearGradient
id="gradient_2"
gradientUnits="userSpaceOnUse"
x1="383.45288"
y1="318.2124"
x2="295.73892"
y2="203.79875"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#BF9029"
id="stop9" />
<stop
offset="1"
stop-color="#F5D354"
id="stop10" />
</linearGradient>
</defs>
<path
fill="url(#gradient_2)"
d="m 434.37375,137.51566 c 2.598,-0.164 5.328,-0.374 7.914,0 44.516,7.77801 92.47,33.43601 126.896,61.38602 7.438,7.668 16.4,14.876 22.864,23.372 2.62,2.794 5.176,5.692 8.21,8.044 5.566,3.826 22.78,23.15001 28.692,29.00401 l 0.008,0.522 c 0.052,5.284 2.926,14.418 2.624,16.914 1.07,8.98 6.816,17.276 9.974,25.644 32.534,86.22402 17.178,181.23004 -38.442,254.80205 -9.59,12.686 -20.71,25.49601 -33.178,35.41401 -3.856,3.068 -7.42,3.966 -0.752,4.206 -9.394,1.774 -23.42,-0.584 -32.986,-1.972 -4.678,-1.616 -8.764,-3.286 -12.892,-6.05 12.516,-9.682 25.068,-17.99401 36.6,-29.13801 4.686,-6.356 10.676,-11.66 15.55,-17.874 81.026,-103.29002 65.494,-245.72405 -39.258,-327.17806 l -3.008,-1.8 c -2.044,9.138 -0.448,19.068 -3.058,28.048 -20.19,-16.736 -57.964,-41.348 -84.916,-44.78 -4.862,6.39 -8.658,12.616 -14.43,18.532 -7.806,8.378 -15.312,17.27 -22.424,26.248 v -3.898 c -1.506,1.596 -4.512,4.54 -4.34,6.828 l 0.516,0.474 c -0.566,1.138 -1.052,2.3 -1.93,3.238 l -1.24,0.028 0.2,1.06001 c -4.05,-8.60801 1.232,-15.75801 3.436,-23.75601 26.818,-41.54401 24.194,-53.60601 -19.526,-73.22601 16.782,-3.452 30.824,-15.02601 48.896,-14.09201 z"
id="path10"
style="fill:url(#gradient_2);stroke-width:2" />
<path
fill="#e7aa1f"
d="m 592.04775,222.27368 c 2.62,2.794 5.176,5.692 8.21,8.044 8.066,13.52 19.78,29.05401 28.692,42.98401 -6.366,-3.072 -23.312,-30.26801 -30.038,-38.90201 -2.778,-3.566 -7.95,-7.296 -6.864,-12.126 z"
id="path11"
style="stroke-width:2" />
<path
fill="#051053"
d="m 600.25775,230.31768 c 5.566,3.826 22.78,23.15001 28.692,29.00401 l 0.008,0.522 c 0.052,5.284 2.926,14.418 2.624,16.914 -0.81,-1.204 -1.734,-2.318 -2.632,-3.456 -8.912,-13.93 -20.626,-29.46401 -28.692,-42.98401 z"
id="path12"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 536.19775,214.61168 c -9.436,-16.308 -80.554,-44.98201 -95.5,-43.60601 -2.88,-2.338 -5.638,-6.154 -7.546,-9.334 13.846,-0.878 61.092,18.238 74.408,25.094 7.224,3.72 43.202,27.84801 43.214,27.84601 3.21,2.37 5.956,5.258 9.132,7.662 4.042,5.416 9.626,9.648 14.302,14.496 93.102,96.54202 79.466,249.74005 -15.778,339.83206 -3.328,3.14801 -18.614,17.85401 -22.232,18.25001 -4.678,-1.616 -8.764,-3.286 -12.892,-6.05 12.516,-9.682 25.068,-17.99401 36.6,-29.13801 4.686,-6.356 10.676,-11.66 15.55,-17.874 81.026,-103.29002 65.494,-245.72405 -39.258,-327.17806 z"
id="path13"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 434.37375,137.51566 c 2.598,-0.164 5.328,-0.374 7.914,0 44.516,7.77801 92.47,33.43601 126.896,61.38602 2.568,7.928 14.072,10.708 15.774,18.372 l -0.474,0.94 -2.092,0.246 c -0.048,0.186 -10.608,12.996 -11.95,12.526 -3.166,-1.106 -7.656,-9.138 -10.536,-8.712 -3.176,-2.404 -5.922,-5.292 -9.132,-7.662 -0.012,0.002 -35.99,-24.12601 -43.214,-27.84601 -13.316,-6.856 -60.562,-25.972 -74.408,-25.094 1.908,3.18 4.666,6.996 7.546,9.334 14.946,-1.376 86.064,27.29801 95.5,43.60601 l -3.008,-1.8 c -2.044,9.138 -0.448,19.068 -3.058,28.048 -20.19,-16.736 -57.964,-41.348 -84.916,-44.78 -4.862,6.39 -8.658,12.616 -14.43,18.532 -7.806,8.378 -15.312,17.27 -22.424,26.248 v -3.898 c -1.506,1.596 -4.512,4.54 -4.34,6.828 l 0.516,0.474 c -0.566,1.138 -1.052,2.3 -1.93,3.238 l -1.24,0.028 0.2,1.06001 c -4.05,-8.60801 1.232,-15.75801 3.436,-23.75601 26.818,-41.54401 24.194,-53.60601 -19.526,-73.22601 16.782,-3.452 30.824,-15.02601 48.896,-14.09201 z"
id="path14"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 412.09175,152.87167 c 12.74,-3.468 25.54,-4.784 38.71,-3.946 -6.848,2.32 -14.484,5.572 -20.016,10.326 8.062,3.682 21.354,5.528 30.612,8.39 19.908,6.152 75.712,30.48001 89.376,46.97001 -0.012,0.002 -35.99,-24.12601 -43.214,-27.84601 -13.316,-6.856 -60.562,-25.972 -74.408,-25.094 1.908,3.18 4.666,6.996 7.546,9.334 14.946,-1.376 86.064,27.29801 95.5,43.60601 l -3.008,-1.8 c -17.866,-18.572 -65.548,-36.19801 -90.902,-40.93001 3.608,7.782 6.348,15.752 2.928,24.19801 -4.862,6.39 -8.658,12.616 -14.43,18.532 -7.806,8.378 -15.312,17.27 -22.424,26.248 v -3.898 c 22.078,-32.98 57.308,-46.31801 3.73,-84.09001 z"
id="path15"
style="stroke-width:2" />
<path
fill="#f1ead8"
d="m 442.28775,171.88167 c 25.354,4.732 73.036,22.35801 90.902,40.93001 -2.044,9.138 -0.448,19.068 -3.058,28.048 -20.19,-16.736 -57.964,-41.348 -84.916,-44.78 3.42,-8.44601 0.68,-16.41601 -2.928,-24.19801 z"
id="path16"
style="stroke-width:2" />
<defs
id="defs17">
<linearGradient
id="gradient_3"
gradientUnits="userSpaceOnUse"
x1="259.85068"
y1="248.27858"
x2="350.85385"
y2="408.95212"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#061757"
id="stop16" />
<stop
offset="1"
stop-color="#1C4897"
id="stop17" />
</linearGradient>
</defs>
<path
fill="url(#gradient_3)"
d="m 628.94975,259.32169 c 35.888,36.25 71.52,72.79001 107.964,108.48002 6.736,6.598 18.816,21.616 24.91,26.196 1.264,13.294 -0.766,28.52001 -2.266,41.84201 -22.772,202.34804 -192.312,343.02406 -397.788,324.19806 -2.656,-0.244 -8.104,-0.266 -10.378,-1.552 -4.572,-6.652 -23.912,-22.76601 -31.626,-30.48801 l -117.162,-117.50802 c -11.006,-10.966 -46.288,-42.43401 -53.304,-54.48401 -4.57,-5.32 -10.27,-9.648 -14.854,-15.058 4.872,0.144 18.938,7.52 23.586,10.336 6.858,1.708 20.052,4.126 26.25,6.798 0.434,-1.258 0.146,-2.694 0,-3.998 0.138,-1.692 0.09,-3.306 0,-5 3.348,0.634 6.652,2.408 10.05,2.2 13.202,5.656 24.534,12.708 34.05,23.62 3.788,3.09 7.482,6.23801 11.126,9.49601 4.716,4.008 9.52,7.936 13.794,12.424 1.884,0.704 5.45,2.046 6.762,3.614 1.584,0.97 3.154,2.014 4.78,2.904 7.256,3.166 14.768,8.762 21.092,13.49 1.516,2.334 3.288,4.486 5.016,6.664 l 7.45,10.00201 c 3.628,5.182 7.178,10.882 11.632,15.38 l 0.164,0.692 c 9.148,5.082 37.618,11.66 48.31,12.01 16.476,-3.154 25.676,-0.374 41.264,0.02 14.094,0.358 28.456,-1.964 42.516,-0.02 6.952,0.73 32.98,-4.094 37.886,-8.6 7.398,7.31 18.44,8.658 28.374,7.392 40.55,-5.168 97.53,-34.27201 123.034,-67.37801 -2.714,-0.424 9.054,-10.22 9.25,-12.97 -7.204,1.354 -10.72,9.924 -18.264,10.996 -3.768,2.22 -7.816,4.312 -11.16,7.146 -1.202,-0.71 -2.33,-1.008 -3.666,-1.342 1.196,-1.606 1.978,-2.98 2.604,-4.89 l 1.062,-3.132 c -13.996,4.118 -27.662,6.834 -42.224,8.022 -6.668,-0.24 -3.104,-1.138 0.752,-4.206 12.468,-9.918 23.588,-22.72801 33.178,-35.41401 55.62,-73.57201 70.976,-168.57803 38.442,-254.80205 -3.158,-8.368 -8.904,-16.664 -9.974,-25.644 0.302,-2.496 -2.572,-11.63 -2.624,-16.914 z"
id="path17"
style="fill:url(#gradient_3);stroke-width:2" />
<path
fill="#fade6b"
d="m 637.21175,576.96974 c 4.14,-2.36 8.288,-4.69 12.494,-6.932 -5.274,7.16 -11.4,17.29401 -18.124,22.95601 -2.714,-0.424 9.054,-10.22 9.25,-12.97 -7.204,1.354 -10.72,9.924 -18.264,10.996 3.782,-3.136 14.3,-8.644 15.882,-12.846 z"
id="path18"
style="stroke-width:2" />
<path
fill="#f2e8a9"
d="m 637.21175,576.96974 1.238,1.20401 c -1.582,4.202 -12.1,9.71 -15.882,12.846 -3.768,2.22 -7.816,4.312 -11.16,7.146 -1.202,-0.71 -2.33,-1.008 -3.666,-1.342 1.196,-1.606 1.978,-2.98 2.604,-4.89 l 1.062,-3.132 c 9.172,-3.09 17.482,-6.914 25.804,-11.83201 z"
id="path19"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 358.50775,661.57976 c 16.476,-3.154 25.676,-0.374 41.264,0.02 14.094,0.358 28.456,-1.964 42.516,-0.02 -25.31,6.146 -58.224,4.784 -83.78,0 z"
id="path20"
style="stroke-width:2" />
<defs
id="defs21">
<linearGradient
id="gradient_4"
gradientUnits="userSpaceOnUse"
x1="178.9133"
y1="342.13019"
x2="155.9601"
y2="362.37878"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#CC991E"
id="stop20" />
<stop
offset="1"
stop-color="#F2B831"
id="stop21" />
</linearGradient>
</defs>
<path
fill="url(#gradient_4)"
d="m 134.44575,540.94774 c 4.872,0.144 18.938,7.52 23.586,10.336 6.858,1.708 20.052,4.126 26.25,6.798 0.434,-1.258 0.146,-2.694 0,-3.998 0.138,-1.692 0.09,-3.306 0,-5 3.348,0.634 6.652,2.408 10.05,2.2 13.202,5.656 24.534,12.708 34.05,23.62 3.788,3.09 7.482,6.23801 11.126,9.49601 4.716,4.008 9.52,7.936 13.794,12.424 1.884,0.704 5.45,2.046 6.762,3.614 1.584,0.97 3.154,2.014 4.78,2.904 7.256,3.166 14.768,8.762 21.092,13.49 1.516,2.334 3.288,4.486 5.016,6.664 l 7.45,10.00201 c 3.628,5.182 7.178,10.882 11.632,15.38 l 0.164,0.692 c -22.282,-4.896 -55.696,-23.88201 -74.236,-37.44601 -6.744,-4.934 -12.552,-11.388 -19.652,-15.766 -6.676,-4.12 -15.06,-5.966 -22.186,-9.388 -16.632,-7.988 -30.922,-18.98801 -44.824,-30.96401 -4.57,-5.32 -10.27,-9.648 -14.854,-15.058 z"
id="path21"
style="fill:url(#gradient_4);stroke-width:2" />
<path
fill="#d6991c"
d="m 158.03175,551.28374 c 6.858,1.708 20.052,4.126 26.25,6.798 1.448,0.596 2.168,1.102 2.948,2.48 l -0.558,0.666 c -3.77,-0.136 -27.166,-8.046 -28.64,-9.944 z"
id="path22"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 242.85175,607.32775 c 7.25,0.168 31.11,8.666 40.444,11.75 -14.638,0.038 -27.2,-6.238 -40.444,-11.75 z"
id="path23"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 232.69375,596.82375 c 6.662,0.62 22.044,5.462 27.37,3.614 1.584,0.97 3.154,2.014 4.78,2.904 -4.194,1.55 -18.89,-0.318 -26.814,1.446 z"
id="path24"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 209.78375,574.90374 c -2.394,-0.948 -7.676,-3.032 -7.456,-6.196 5.142,-1.48 19.682,5.378 26.054,6.196 3.788,3.09 7.482,6.23801 11.126,9.49601 l -0.16,0.142 c -3.374,0.606 -25.568,-7.70801 -29.564,-9.63801 z"
id="path25"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 209.78375,574.90374 c 3.996,1.93 26.19,10.24401 29.564,9.63801 l 0.16,-0.142 c 4.716,4.008 9.52,7.936 13.794,12.424 1.884,0.704 5.45,2.046 6.762,3.614 -5.326,1.848 -20.708,-2.994 -27.37,-3.614 -10.77,-1.75 -16.314,-4.876 -19.558,-16.004 -1.528,-1.78 -2.85,-3.59801 -3.352,-5.91601 z"
id="path26"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 209.78375,574.90374 c 3.996,1.93 26.19,10.24401 29.564,9.63801 l 0.16,-0.142 c 4.716,4.008 9.52,7.936 13.794,12.424 v 0 c -11.244,-0.884 -22.286,-6.858 -31.866,-12.424 -2.804,-0.374 -5.434,-2.774 -8.3,-3.58 -1.528,-1.78 -2.85,-3.59801 -3.352,-5.91601 z"
id="path27"
style="stroke-width:2" />
<path
fill="#ad7214"
d="m 221.43575,584.39975 c 6.578,-0.56 30.096,8.298 31.866,12.424 -11.244,-0.884 -22.286,-6.858 -31.866,-12.424 z"
id="path28"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 266.41175,531.65974 c -4.998,-0.03 -11.098,-9.27801 -14.01,-12.81601 -78.2,-95.08401 -44.296,-239.09604 68.622,-289.88605 14.626,-6.58 87.39,-28.004 83.98,-12.018 0.29,5.32 -5.89,12.826 -5.742,19.654 l 0.8,-0.356 0.256,-0.984 c 0.838,-3.116 3.132,-7.658 4.686,-10.42 v 0 c -2.204,7.998 -7.486,15.148 -3.436,23.75601 l -0.2,-1.06001 1.24,-0.028 c 0.878,-0.938 1.364,-2.1 1.93,-3.238 l -0.516,-0.474 c -0.172,-2.288 2.834,-5.232 4.34,-6.828 v 3.898 c 7.112,-8.978 14.618,-17.87 22.424,-26.248 l 0.5,0.152 c 8.212,2.444 16.47,3.944 24.602,6.854 58.574,20.972 106.85,72.05001 120.456,133.45202 1.73,7.81001 2.632,15.79601 4.472,23.57201 0.174,4.016 1.316,11.12 -0.142,14.692 l -1.322,0.664 1.154,0.176 c 1.286,3.432 0.364,9.786 0.31,13.526 0.428,4.816 0.606,10.62001 0,15.40801 -1.662,4.574 -2.66,9.378 -3.582,14.148 -0.862,5.382 -1.694,10.842 -3.742,15.924 -1.502,3.656 -3.308,7.462 -4.308,11.294 -0.442,4.27201 -3.664,10.89601 -6.116,14.42401 -2.28,4.28 -4.82,10.524 -8.172,14.028 -2.766,4.198 -5.424,8.452 -8.062,12.73 l -10.636,13.256 c -0.812,1.354 -10.158,11.70601 -11.41,12.74801 -4.732,2.976 -7.86,5.02 -11.552,9.288 -4.794,2.344 -9.02,6.04 -13.816,8.136 -4.916,2.576 -9.95,5.226 -14.068,8.998 -5.336,1.804 -10.23,3.636 -15.1,6.486 -3,0.812 -11.478,3.87 -14.124,3.644 -5.37,1.882 -11.066,2.43 -16.396,4.486 l -14.888,2.206 c -3.228,-0.058 -14.524,1.172 -16.482,0 -2.668,0.884 -14.2,-1.2 -17.154,-2.206 -4.388,-1.97 -13.234,-3.4 -15.17,-4.486 -15.284,-4 -26.706,-61.61201 4.84,-58.55001 5.12,0.178 10.212,1.104 15.266,1.896 -0.322,-4.59 -1.47,-8.966 -2.758,-13.362 -31.792,-69.38401 -101.182,-95.30202 -174.692,-84.31001 28.904,2.816 52.742,14.29 77.006,28.634 14.684,13.388 42.828,39.46001 22.146,59.30801 -4.42,-5.66 -9.796,-10.928 -13.456,-17.124 l -1.134,0.23 0.924,-0.544 0.246,0.612 -1.168,-0.966 c -0.378,1.04 0.1,2.79 0.238,3.908 -0.494,8.656 -0.63,17.812 -1.922,26.378 -0.986,1.08 -1.914,2.264 -3.172,3.032 -4.348,3.636 -8.422,7.43801 -12.466,11.40401 -1.992,-3.07 -5.034,-6.59401 -6.57,-9.84601 -2.598,-1.562 -2.622,-4.334 -3.65,-6.816 l -0.892,0.308 c -0.248,2.022 1.28,3.668 1.268,5.77 l -0.744,0.738 c 2.36,3.862 7.746,10.52601 7.948,15.01601 -5.642,-0.656 -11.25,-1.548 -16.884,-2.268 z"
id="path29"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 271.23775,505.65573 4.11,2.688 c 0.612,3.864 2.48,7.024 4.018,10.568 -2.598,-1.562 -2.622,-4.334 -3.65,-6.816 l -0.892,0.308 c -0.248,2.022 1.28,3.668 1.268,5.77 l -0.744,0.738 c -1.114,-4.514 -3.114,-8.68 -4.11,-13.256 z"
id="path30"
style="stroke-width:2" />
<path
fill="#051053"
d="m 397.67375,507.07373 c 2.356,4.01 4.79,7.942 7.33,11.838 -3.3,-1.106 -7.652,-4.4 -10.786,-4.59 l 1.848,-0.566 c 1.032,-1.614 0.804,-4.254 1.44,-6.188 z"
id="path31"
style="stroke-width:2" />
<path
fill="#0f0e1a"
d="m 393.38575,498.19573 c 3.194,2.542 2.828,5.462 4.288,8.878 l -0.168,0.494 c -0.636,1.934 -0.408,4.574 -1.44,6.188 l -1.848,0.566 c -4.74,-0.682 -9.642,-1.346 -13.34,-4.66 5.12,0.178 10.212,1.104 15.266,1.896 -0.322,-4.59 -1.47,-8.966 -2.758,-13.362 z"
id="path32"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 405.00375,216.93968 c 0.29,5.32 -5.89,12.826 -5.742,19.654 l 0.8,-0.356 0.256,-0.984 c 0.838,-3.116 3.132,-7.658 4.686,-10.42 v 0 c -2.204,7.998 -7.486,15.148 -3.436,23.75601 l -0.2,-1.06001 1.24,-0.028 c 0.878,-0.938 1.364,-2.1 1.93,-3.238 l -0.516,-0.474 c -0.172,-2.288 2.834,-5.232 4.34,-6.828 v 3.898 c -5.74,7.47601 -10.278,15.97801 -14.976,24.13401 2.614,-16.47 4.536,-32.74201 11.618,-48.05401 z"
id="path33"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 376.03775,568.21174 c 3.14,-7.134 6.892,-14.264 9.44,-21.616 2.51,8.576 3.87,17.374 5.73,26.102 -4.388,-1.97 -13.234,-3.4 -15.17,-4.486 z"
id="path34"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 275.34775,508.34373 c 7.554,3.424 15.174,6.414 23.054,9.01 -4.348,3.636 -8.422,7.43801 -12.466,11.40401 -1.992,-3.07 -5.034,-6.59401 -6.57,-9.84601 -1.538,-3.544 -3.406,-6.704 -4.018,-10.568 z"
id="path35"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 580.81575,378.64171 c 0.174,4.016 1.316,11.12 -0.142,14.692 l -1.322,0.664 c -8.51,-1.606 -16.614,-3.178 -25.25,-4.102 8.398,-6.016 16.886,-8.52 26.714,-11.254 z"
id="path36"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 554.10175,411.69971 c 8.586,-2.24 17.924,-2.716 26.714,-4 0.428,4.816 0.606,10.62001 0,15.40801 -8.872,-2.66 -19.79,-5.044 -26.714,-11.40801 z"
id="path37"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 413.80575,549.08374 c 5.198,7.878 7.314,17.22 11.038,25.82 -3.228,-0.058 -14.524,1.172 -16.482,0 1.018,-8.646 2.216,-17.686 5.444,-25.82 z"
id="path38"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 526.91575,484.43773 c 9.316,1.67 19.154,5.096 27.98,8.488 -2.766,4.198 -5.424,8.452 -8.062,12.73 -7.26,-6.506 -15.232,-12.516 -19.918,-21.218 z"
id="path39"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 549.10575,437.25572 c 9.318,-0.64 18.79,-0.084 28.128,0 -0.862,5.382 -1.694,10.842 -3.742,15.924 -8.43,-5.086 -16.78,-9.56 -24.386,-15.924 z"
id="path40"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 439.73175,543.29174 1.36,1.452 c 6.326,6.73 9.89,15.802 15.036,23.468 -5.37,1.882 -11.066,2.43 -16.396,4.486 z"
id="path41"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 539.67175,462.21972 c 9.972,-0.004 19.626,1.052 29.512,2.254 -0.442,4.27201 -3.664,10.89601 -6.116,14.42401 -8.166,-3.222 -17.172,-10.556 -23.396,-16.67801 z"
id="path42"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 488.88575,521.69573 c 7.732,3.84201 19.168,12.47201 24.35,19.25201 -4.794,2.344 -9.02,6.04 -13.816,8.136 -4.688,-8.85 -7.936,-17.748 -10.534,-27.38801 z"
id="path43"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 509.94175,505.65573 c 5.494,1.07 8.69,2.82 13.364,5.902 5.104,1.702 8.644,4.112 12.892,7.354 -0.812,1.354 -10.158,11.70601 -11.41,12.74801 -2.844,-4.58 -6.188,-9.33401 -8.274,-14.30601 -2.536,-3.532 -4.474,-7.872 -6.572,-11.698 z"
id="path44"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 465.35375,533.92774 c 7.502,6.24 15.294,15.644 19.998,24.154 -5.336,1.804 -10.23,3.636 -15.1,6.486 -3.214,-9.588 -4.238,-20.568 -4.898,-30.64 z"
id="path45"
style="stroke-width:2" />
<path
fill="#2356ae"
d="M 351.39175,758.48578 C 168.77575,730.12777 41.748945,587.64375 38.358945,403.44571 34.725145,206.00568 197.09775,42.52665 394.25175,39.316449 c 199.908,-3.255 364.866,156.319231 367.572,354.681261 -6.094,-4.58 -18.174,-19.598 -24.91,-26.196 -36.444,-35.69001 -72.076,-72.23002 -107.964,-108.48002 -5.912,-5.854 -23.126,-25.17801 -28.692,-29.00401 -3.034,-2.352 -5.59,-5.25 -8.21,-8.044 -6.464,-8.496 -15.426,-15.704 -22.864,-23.372 -34.426,-27.95001 -82.38,-53.60801 -126.896,-61.38602 -2.586,-0.374 -5.316,-0.164 -7.914,0 -18.072,-0.934 -32.114,10.64001 -48.896,14.09201 43.72,19.62 46.344,31.682 19.526,73.22601 v 0 c -1.554,2.762 -3.848,7.304 -4.686,10.42 l -0.256,0.984 -0.8,0.356 c -0.148,-6.828 6.032,-14.334 5.742,-19.654 3.41,-15.986 -69.354,5.438 -83.98,12.018 -112.918,50.79001 -146.822,194.80204 -68.622,289.88605 2.912,3.538 9.012,12.78601 14.01,12.81601 5.634,0.72 11.242,1.612 16.884,2.268 -0.202,-4.49 -5.588,-11.15401 -7.948,-15.01601 l 0.744,-0.738 c 0.012,-2.102 -1.516,-3.748 -1.268,-5.77 l 0.892,-0.308 c 1.028,2.482 1.052,5.254 3.65,6.816 1.536,3.252 4.578,6.77601 6.57,9.84601 4.044,-3.966 8.118,-7.76801 12.466,-11.40401 1.258,-0.768 2.186,-1.952 3.172,-3.032 1.292,-8.566 1.428,-17.722 1.922,-26.378 -0.138,-1.118 -0.616,-2.868 -0.238,-3.908 l 1.168,0.966 -0.246,-0.612 -0.924,0.544 1.134,-0.23 c 3.66,6.196 9.036,11.464 13.456,17.124 20.682,-19.848 -7.462,-45.92001 -22.146,-59.30801 8.322,2.714 22.978,21.546 26.672,29.42201 2.368,5.048 2.81,14.832 4.236,17.488 3.938,-9.238 -6.242,-21.60201 -4.594,-23.16201 6.228,12.53801 9.19,23.92001 0,35.56001 -11.034,9.136 -29.284,21.156 -36.122,33.99601 -15.95,29.946 -3.004,58.48801 7.948,85.92401 1.766,3.338 5.028,8.098 5.668,11.75001 h -1.106 l -7.45,-10.00201 c -1.728,-2.178 -3.5,-4.33 -5.016,-6.664 -6.324,-4.728 -13.836,-10.324 -21.092,-13.49 -1.626,-0.89 -3.196,-1.934 -4.78,-2.904 -1.312,-1.568 -4.878,-2.91 -6.762,-3.614 -4.274,-4.488 -9.078,-8.416 -13.794,-12.424 -3.644,-3.258 -7.338,-6.40601 -11.126,-9.49601 -9.516,-10.912 -20.848,-17.964 -34.05,-23.62 -3.398,0.208 -6.702,-1.566 -10.05,-2.2 0.09,1.694 0.138,3.308 0,5 0.146,1.304 0.434,2.74 0,3.998 -6.198,-2.672 -19.392,-5.09 -26.25,-6.798 -4.648,-2.816 -18.714,-10.192 -23.586,-10.336 4.584,5.41 10.284,9.738 14.854,15.058 7.016,12.05 42.298,43.51801 53.304,54.48401 l 117.162,117.50802 c 7.714,7.722 27.054,23.83601 31.626,30.48801 z"
id="path46"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 179.65375,204.78568 0.312,-1.174 0.54,0.326 c 1.66,8.908 0.01,23.462 3.776,31.23 -0.946,2.464 -0.94,5.09 -2.088,7.614 -0.896,-7.214 -1.61,-14.446 -2.54,-21.656 -0.13,-5.46 -0.212,-10.878 0,-16.34 z"
id="path47"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 125.81775,276.75769 c 2.17,11.74 9.116,22.444 12.934,33.79201 l -0.57,0.518 c -1.16,-3.654 -7.662,-20.46601 -9.84,-22.36001 l -0.976,0.068 c -1.38,1.692 -2.846,2.256 -4.866,3.024 -2.616,6.924 -1.898,24.47801 -3.168,33.15201 -0.472,-15.43 -0.356,-34.15801 6.486,-48.19401 z"
id="path48"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 274.23575,141.76967 c -2.074,7.182 -3.328,13.142 -2.998,20.634 -4.176,2.324 -7.592,4.762 -11.174,7.91 v -2.354 c 1.878,-6.262 2.766,-12.768 4.78,-19.034 3.524,-1.72 6.27,-4.824 9.392,-7.156 z"
id="path49"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 371.74975,108.36966 c -3.86,7.4 -7.354,14.524 -9.404,22.688 v 0 c -3.648,0.82 -7.228,1.122 -10.954,1.38 4.392,-6.38 5.642,-13.5 10.954,-19.87 l 1.312,1.376 c 2.71,-0.242 5.8,-4.024 8.092,-5.574 z"
id="path50"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 268.33575,131.05766 c -1.042,5.972 -2.31,11.92001 -3.492,17.86801 -2.014,6.266 -2.902,12.772 -4.78,19.034 -1.326,-4.864 3.318,-9.734 1.244,-14.208 -22.57,-10.084 -17.62,14.712 -26.708,18.13 6.172,-15.816 20.434,-30.548 33.736,-40.82401 z"
id="path51"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 179.65375,196.07968 c -0.244,2.936 -0.14,5.77 0,8.706 -0.212,5.462 -0.13,10.88 0,16.34 -2.87,1.676 -3.574,6.084 -4.174,9.192 -1.636,3.874 -3.642,7.834 -4.67,11.914 l -0.244,0.106 0.41,-0.728 -0.192,-0.106 c 2.75,-11.394 5.076,-8.03 -4.17,-11.186 -1.178,2.228 -4.1,9.672 -5.944,10.542 4.934,-15.602 12.448,-29.868 18.984,-44.78 z"
id="path52"
style="stroke-width:2" />
<path
fill="#132b6d"
d="m 456.12775,109.52166 c 3.564,1.658 10.414,-0.138 14.124,-1.152 -9.878,8.046 -21.92,17.846 -27.964,29.146 -2.586,-0.374 -5.316,-0.164 -7.914,0 l -6.334,-3.096 c 7.916,-6.85 14.976,-14.806 22.762,-21.852 1.752,-1.066 3.52,-2.074 5.326,-3.046 z"
id="path53"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 100.50375,364.60771 c 8.122,7.8 22.772,25.956 30.762,31.252 0.936,5.038 2.374,10.71 2.462,15.774 -12.286,-9.396 -17.796,-19.394 -28.126,-27.642 0.096,1.026 0.082,1.858 -0.212,2.84 -2.522,-7.432 -3.886,-14.462 -4.886,-22.224 z"
id="path54"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 96.515745,442.51972 c 8.566005,4.34 36.750005,23.486 42.236005,30.46001 l 0.276,0.808 c 6.398,2.844 8.096,8.69 8.058,15.766 l -0.588,-0.544 c -1.434,-1.32 -10.678,-7.62 -12.052,-7.594 -5.946,-3.566 -23.722,-21.69601 -29.056,-20.70801 -3.03,-6.03 -5.978005,-12.092 -8.874005,-18.188 z"
id="path55"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 121.77975,525.87374 c 19.42,6.36 38.498,14.12 57.874,20.722 l 0.548,0.758 1.826,-0.056 c 1.258,1.488 1.388,4.868 2.254,6.786 0.146,1.304 0.434,2.74 0,3.998 -6.198,-2.672 -19.392,-5.09 -26.25,-6.798 -4.648,-2.816 -18.714,-10.192 -23.586,-10.336 -4.45,-4.812 -8.812,-9.764 -12.666,-15.074 z"
id="path56"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 271.23775,162.40367 c 7.99,-6.254 18.884,-10.416 28.25,-14.234 16.76,-6.832 13.44,-7.376 25.658,-19.48401 10.768,-10.672 29.362,-23.208 44.058,-28.062 -2.508,3.886 -5.042,7.672 -6.858,11.944 -5.312,6.37 -6.562,13.49 -10.954,19.87 -0.974,1.678 -1.832,2.932 -3.262,4.254 l -0.532,-0.056 c 0.956,-3.102 4.54,-2.84 3.518,-6.662 l -2.128,-2.174 c -8.514,3.742 -77.504,34.61201 -77.75,34.60401 z"
id="path57"
style="stroke-width:2" />
<defs
id="defs58">
<linearGradient
id="gradient_5"
gradientUnits="userSpaceOnUse"
x1="145.13785"
y1="328.17804"
x2="117.22018"
y2="280.89636"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#D79A18"
id="stop57" />
<stop
offset="1"
stop-color="#F6C842"
id="stop58" />
</linearGradient>
</defs>
<path
fill="url(#gradient_5)"
d="m 105.38975,460.70772 c 5.334,-0.988 23.11,17.14201 29.056,20.70801 4.286,3.456 9.396,6.13 13.392,9.86 0.278,-2.39 0.424,-4.632 1.462,-6.838 l 0.504,-0.106 c 0.058,-0.954 -0.086,-7.128 0.79,-5.038 1.712,4.084 3.956,1.936 4.492,8.664 l 0.486,-0.014 c 2.38,7.206 8.172,8.99 13.068,13.884 l -0.348,0.398 c 2.612,0.138 4.874,0.24 7.188,1.558 0.816,0.698 1.66,1.344 2.532,1.97 l 0.462,1.048 c -1.04,0.308 -0.606,0.28 -1.274,0.272 3.704,0.932 3.808,4.058 4.994,7.248 v 0 c 2.772,3.696 5.17,7.268 6.946,11.55201 -1.732,-0.248 -24.262,-10.67601 -16.892,-1.472 2.482,3.098 5.226,7.084 8.34,9.526 2.636,1.906 4.292,5.756 7.29,7.02 h 1.262 l -1.262,2.344 c 0.818,1.872 1.938,2.472 3.716,3.304 l -0.66,0.048 c -2.968,0.184 -9.982,-2.572 -6.652,2.44 0.09,1.694 0.138,3.308 0,5 -0.866,-1.918 -0.996,-5.298 -2.254,-6.786 l -1.826,0.056 -0.548,-0.758 c -0.52,-3.778 -6.05,-8.072 -8.808,-10.5 -24.584,-13.75401 -54.27,-50.32801 -65.456,-75.38802 z"
id="path58"
style="fill:url(#gradient_5);stroke-width:2" />
<path
fill="#f1be39"
d="m 170.84575,536.09574 c 0.178,0.002 16.806,6.982 17.032,7.196 0.818,1.872 1.938,2.472 3.716,3.304 l -0.66,0.048 c -2.968,0.184 -9.982,-2.572 -6.652,2.44 0.09,1.694 0.138,3.308 0,5 -0.866,-1.918 -0.996,-5.298 -2.254,-6.786 l -1.826,0.056 -0.548,-0.758 c -0.52,-3.778 -6.05,-8.072 -8.808,-10.5 z"
id="path59"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 182.19375,514.32173 c -5.22,-0.312 -16.074,-7.81 -20,-10.892 -0.398,-0.312 -4.628,-3.938 -2.568,-3.994 4.124,-0.114 11.04,6.52 14.26,8.908 0.87,-0.988 2.086,-1.036 3.314,-1.27 3.704,0.932 3.808,4.058 4.994,7.248 z"
id="path60"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 177.19975,507.07373 c 3.704,0.932 3.808,4.058 4.994,7.248 -2.664,-2.118 -5.5,-4.052 -8.308,-5.978 0.87,-0.988 2.086,-1.036 3.314,-1.27 z"
id="path61"
style="stroke-width:2" />
<defs
id="defs62">
<linearGradient
id="gradient_6"
gradientUnits="userSpaceOnUse"
x1="238.76126"
y1="143.77654"
x2="270.52316"
y2="95.432106"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#FAD84F"
id="stop61" />
<stop
offset="1"
stop-color="#FFF5A9"
id="stop62" />
</linearGradient>
</defs>
<path
fill="url(#gradient_6)"
d="m 362.34575,131.05766 c 26.81,-3.184 19.722,-1.768 42.234,-13.04 19.684,-9.856 41.194,-16.094 63.324,-15.652 -4.056,2.182 -8.086,4.39 -11.776,7.156 -1.806,0.972 -3.574,1.98 -5.326,3.046 -7.786,7.046 -14.846,15.002 -22.762,21.852 l 6.334,3.096 c -18.072,-0.934 -32.114,10.64001 -48.896,14.09201 -3.1,0.442 -6.45,0.35 -9.44,1.264 -3.958,1.83 -9.35,-0.016 -13.526,1.328 l -0.166,0.49 c 4.412,1.276 9.87,1.98 13.692,4.562 -11.014,0.822 -21.384,-2.856 -32.396,-2.412 -0.74,-0.772 -5.22,0.294 -7.562,-0.282 l 0.286,-0.044 c -8.446,-2.598 -0.096,-4.918 2.406,-7.588 6.796,-3.554 22.95,-8.952 23.574,-17.86801 z"
id="path62"
style="fill:url(#gradient_6);stroke-width:2" />
<path
fill="#e4c267"
d="m 341.76375,151.60767 c 11.034,-5.176 26.9,-6.422 39.114,-7.498 -2.7,3.496 -6.968,3.658 -4.84,8.762 -3.958,1.83 -9.35,-0.016 -13.526,1.328 l -0.166,0.49 c -4.888,-1.222 -8.504,-1.066 -13.358,0 -2.746,0.4 -8.482,-0.994 -10.622,-2.552 l 0.184,-0.502 -0.088,0.422 0.506,-0.548 z"
id="path63"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 424.84375,132.43766 c 9.142,-6.23 14.826,-16.674 25.958,-19.87 -7.786,7.046 -14.846,15.002 -22.762,21.852 l 6.334,3.096 c -18.072,-0.934 -32.114,10.64001 -48.896,14.09201 -3.1,0.442 -6.45,0.35 -9.44,1.264 -2.128,-5.104 2.14,-5.266 4.84,-8.762 8.736,-2.842 14.512,-8.95201 24.126,-9.69001 2.98,-2.124 16.504,-3.504 19.84,-1.982 z"
id="path64"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 405.00375,134.41966 c 2.98,-2.124 16.504,-3.504 19.84,-1.982 -3.412,3.298 -15.364,2.648 -19.84,1.982 z"
id="path65"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 348.98775,127.79966 2.128,2.174 c 1.022,3.822 -2.562,3.56 -3.518,6.662 l 0.532,0.056 c 1.43,-1.322 2.288,-2.576 3.262,-4.254 3.726,-0.258 7.306,-0.56 10.954,-1.38 -0.624,8.91601 -16.778,14.31401 -23.574,17.86801 -7.41,2.68 -9.978,8.094 -16.164,11.038 -3.652,1.74 -27.878,3.596 -21.164,11.206 l -1.672,0.284 6.764,0.428 c -13.404,2.41 -17.64,4.718 -29.284,7.922 6.38,1.602 10.798,-2.57 18.448,0.768 h 2.702 l -0.042,1.276 c -7.05,4.88 -18.516,5.498 -27.53,13.56001 -1.344,1.2 -2.83,2.678 -4.418,3.494 -4.23,1.326 -8.724,2.754 -13.11,3.378 -1.89,1.25 -12.68,4.234 -15.272,4.588 v 0 -2.082 l -2.28,-3.718 c -4.61,0.068 -7.042,12.34 -7.368,15.872 -8.018,0.742 -11.65,9.846 -16.818,14.858 -3.88,-1.22 -4.476,2.806 -6.472,5.164 -1.86,1.146 -4.982,3.384 -5.056,5.82 1.124,1.468 1.626,2.97 2.234,4.704 v 0 c -0.316,5.61801 1.456,4.99401 6.442,4.89801 -1.14,1.822 -2.366,3.564 -3.62,5.31 -1.95,2.246 -3.464,4.796 -5.056,7.3 -3.182,5.058 -6.5,9.462 -10.092,14.184 l -0.804,0.272 c -2.854,3.482 -4.438,8.244 -6.946,12.09 0.062,-2.884 0.094,-5.748 0,-8.632 -0.152,-5.29 -0.606,-10.77 0,-16.034 -4.278,6.658 -7.876,14.308 -9.904,21.966 l -0.172,-0.658 c -0.69,-2.716 -0.326,-5.508 -1.658,-8.056 -2.812,3.078 -0.546,7.956 -1.82,11.414 -2.326,1.824 -3.704,3.838 -4.96,6.498 0.362,13.11001 -0.04,26.34401 -0.64,39.44401 -2.058,-8.594 -3.944,-31.802 -5.008,-35.10001 -1.466,3.81001 -4.786,9.06401 -5.378,12.93801 -1.004,6.558 0.336,12.898 -1.634,19.682 l -0.152,-2.372 c -1.242,0.97 -0.692,3.5 -1.568,4.852 -0.888,5.956 -6.352,24.62201 -2.024,29.02001 l 1.026,-0.056 c 0.982,-1.328 1.022,-2.274 0.998,-3.888 2.54,11.112 6.984,15.086 6.272,27.338 -4.292,-5.588 -5.538,-12.7 -9.37,-18.494 -3.122,10.1 -3.688,19.896 -1.048,30.034 0.382,1.46 5.496,9.346 2.684,9.412 -1.922,-1.014 -3.814,-2.066 -5.696,-3.148 v 6.18601 l 5.696,5.592 -0.786,0.856 c 0.296,2.89 2.728,6.41 -0.85,8.024 -1.37,-0.752 -2.74,-1.49 -4.06,-2.326 1.508,3.706 4.194,6.776 5.696,10.326 -5.51,8.998 8.018,9.652 6.644,16.822 -2.168,-1.12 -4.022,-2.238 -6.51,-2.394 l -0.58,0.476 c 1.212,3.574 5.104,5.87 8.18,7.788 l 0.106,0.944 c 2.112,1.702 5.154,3.652 6.672,5.856 l -0.092,0.576 c -1.6,-0.072 -10.62,-4.306 -6.686,-0.158 3.098,4.66401 7.5,8.32001 11.042,12.63001 1.028,1.378 2.036,2.636 2.66,4.248 l -0.342,0.572 c -2.3,-0.9 -3.438,-2.91 -5.976,-3.28 2.058,3.032 5.576,4.756 7.89,7.506 -6.846,-3.492 -13.43,-7.156 -19.826,-11.44 1.408,2.746 2.824,5.372 4.552,7.934 -0.206,1.33 -0.332,2.17 0,3.506 l -0.486,0.014 c -0.536,-6.728 -2.78,-4.58 -4.492,-8.664 -0.876,-2.09 -0.732,4.084 -0.79,5.038 l -0.504,0.106 c -1.038,2.206 -1.184,4.448 -1.462,6.838 -3.996,-3.73 -9.106,-6.404 -13.392,-9.86 1.374,-0.026 10.618,6.274 12.052,7.594 l 0.588,0.544 c 0.038,-7.076 -1.66,-12.922 -8.058,-15.766 l -0.276,-0.808 c 1.184,0.176 3.7,2.69 4.754,3.524 -1.57,-16.19201 -6.668,-17.95401 -15.372,-31.30601 -8.38,-12.854 -23.376,-43.43601 -22.744,-58.36601 0.294,-0.982 0.308,-1.814 0.212,-2.84 10.33,8.248 15.84,18.246 28.126,27.642 -0.088,-5.064 -1.526,-10.736 -2.462,-15.774 0.614,-23.334 -11.684,-42.03401 -11.934,-70.90801 1.27,-8.674 0.552,-26.22801 3.168,-33.15201 2.02,-0.768 3.486,-1.332 4.866,-3.024 l 0.976,-0.068 c 2.178,1.894 8.68,18.70601 9.84,22.36001 l 0.57,-0.518 c 1.386,0.9 2.382,2.54 3.39,3.858 1.862,-13.02001 6.618,-19.94201 9.452,-31.46801 3.608,-14.66 3.426,-26.278 9.076,-42.08001 1.844,-0.87 4.766,-8.314 5.944,-10.542 9.246,3.156 6.92,-0.208 4.17,11.186 l 0.192,0.106 -0.41,0.728 0.244,-0.106 c 1.028,-4.08 3.034,-8.04 4.67,-11.914 0.6,-3.108 1.304,-7.516 4.174,-9.192 0.93,7.21 1.644,14.442 2.54,21.656 1.148,-2.524 1.142,-5.15 2.088,-7.614 8.798,-9.326 16.32,-19.906 24.89,-29.486 4.756,-5.318 10.938,-9.912 15.132,-15.63401 4.15,-5.656 5.632,-12.712 10.296,-18.166 9.088,-3.418 4.138,-28.214 26.708,-18.13 2.074,4.474 -2.57,9.344 -1.244,14.208 v 2.354 c 3.582,-3.148 6.998,-5.586 11.174,-7.91 v 0 c 0.246,0.008 69.236,-30.86201 77.75,-34.60401 z"
id="path66"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 182.19375,266.87369 c 0.564,-0.782 2.61,-7.412 3.094,-3.452 0.322,2.642 1.102,21.51 -3.094,19.486 -0.152,-5.29 -0.606,-10.77 0,-16.034 z"
id="path67"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 125.81775,310.5497 c 2.45,2.318 5.498,11.792 7.544,15.398 2.698,4.748 6.998,5.738 5.39,11.534 l -0.768,0.906 -0.92,-0.342 c -4.658,-6.078 -8.65,-19.842 -11.246,-27.496 z"
id="path68"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 238.02975,204.78568 c 5.564,-5.62 15.092,-21.80401 23.426,-22.17401 -1.03,1.272 -5.95,6.208 -5.208,7.716 -1.792,1.966 -4.054,3.62801 -5.628,5.75201 -3.67,1.584 -4.516,5.316 -6.108,8.706 2.69,-0.91 5.97,-2.338 8.79,-2.506 -1.89,1.25 -12.68,4.234 -15.272,4.588 v 0 z"
id="path69"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 295.69975,180.57167 h 2.702 c -8.5,7.116 -21.784,5.136 -31.99,7.612 -3.338,1.062 -6.97,1.058 -10.164,2.144 -0.742,-1.508 4.178,-6.444 5.208,-7.716 1.96,-1.942 7.53,-0.964 9.782,0 8.094,-2.064 16.232,-1.644 24.462,-2.04 z"
id="path70"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 261.45575,182.61167 c 1.96,-1.942 7.53,-0.964 9.782,0 -9.012,0.558 -6.586,5.252 -4.826,5.572 -3.338,1.062 -6.97,1.058 -10.164,2.144 -0.742,-1.508 4.178,-6.444 5.208,-7.716 z"
id="path71"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 200.03575,242.78168 c 1.124,1.468 1.626,2.97 2.234,4.704 v 0 c -0.316,5.61801 1.456,4.99401 6.442,4.89801 -1.14,1.822 -2.366,3.564 -3.62,5.31 -1.95,2.246 -3.464,4.796 -5.056,7.3 -3.182,5.058 -6.5,9.462 -10.092,14.184 l -0.804,0.272 c 0.992,-2.136 -0.112,-2.814 -0.734,-4.852 -1.902,-6.224 8.246,-26.224 11.63,-31.81601 z"
id="path72"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 202.26975,247.48568 v 0 c -0.316,5.61801 1.456,4.99401 6.442,4.89801 -1.14,1.822 -2.366,3.564 -3.62,5.31 -1.95,2.246 -3.464,4.796 -5.056,7.3 -0.992,-6.32 1.244,-11.428 2.234,-17.50801 z"
id="path73"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 298.40175,180.57167 -0.042,1.276 c -7.05,4.88 -18.516,5.498 -27.53,13.56001 -1.344,1.2 -2.83,2.678 -4.418,3.494 -4.23,1.326 -8.724,2.754 -13.11,3.378 -2.82,0.168 -6.1,1.596 -8.79,2.506 1.592,-3.39 2.438,-7.122 6.108,-8.706 1.574,-2.124 3.836,-3.78601 5.628,-5.75201 3.194,-1.086 6.826,-1.082 10.164,-2.144 10.206,-2.476 23.49,-0.496 31.99,-7.612 z"
id="path74"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 271.23775,193.48968 c -1.194,1.158 -4.558,3.824 -4.826,5.412 -4.23,1.326 -8.724,2.754 -13.11,3.378 -2.82,0.168 -6.1,1.596 -8.79,2.506 1.592,-3.39 2.438,-7.122 6.108,-8.706 6.902,-0.504 13.82,-1.276 20.618,-2.59 z"
id="path75"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 149.29975,466.26772 c -9.304,-9.342 -10.01,-43.218 -10.518,-57.68401 -0.538,-15.364 -1.234,-63.88401 4.522,-71.25001 l 0.256,0.428 -0.55,-0.498 c 0.858,0.034 1.536,1.384 3.084,1.57 -0.638,1.076 -2.192,1.04 -2.766,2.208 -3.374,6.87 -7.36,60.42401 -3.304,71.67401 l 1.144,0.50401 0.542,-0.48001 c -0.028,-1.786 0.016,-3.3 0.432,-5.04 v 6.18601 l 5.696,5.592 -0.786,0.856 c 0.296,2.89 2.728,6.41 -0.85,8.024 -1.37,-0.752 -2.74,-1.49 -4.06,-2.326 1.508,3.706 4.194,6.776 5.696,10.326 -5.51,8.998 8.018,9.652 6.644,16.822 -2.168,-1.12 -4.022,-2.238 -6.51,-2.394 l -0.58,0.476 c 1.212,3.574 5.104,5.87 8.18,7.788 l 0.106,0.944 c 2.112,1.702 5.154,3.652 6.672,5.856 l -0.092,0.576 c -1.6,-0.072 -10.62,-4.306 -6.686,-0.158 3.098,4.66401 7.5,8.32001 11.042,12.63001 1.028,1.378 2.036,2.636 2.66,4.248 l -0.342,0.572 c -2.3,-0.9 -3.438,-2.91 -5.976,-3.28 2.058,3.032 5.576,4.756 7.89,7.506 -6.846,-3.492 -13.43,-7.156 -19.826,-11.44 1.408,2.746 2.824,5.372 4.552,7.934 -0.206,1.33 -0.332,2.17 0,3.506 l -0.486,0.014 c -0.536,-6.728 -2.78,-4.58 -4.492,-8.664 -0.876,-2.09 -0.732,4.084 -0.79,5.038 l -0.504,0.106 c 0.334,-4.398 -0.07,-7.204 1.72,-11.458 -1.008,-2.202 -1.76,-4.234 -1.72,-6.71201 z"
id="path76"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 149.29975,466.26772 c 2.55,1.562 4.34,4.17401 5.39,6.94401 l -0.242,0.898 c -1.33,0.158 -2.298,-0.53 -3.428,-1.13 -1.008,-2.202 -1.76,-4.234 -1.72,-6.71201 z"
id="path77"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 234.59975,171.88167 c 9.088,-3.418 4.138,-28.214 26.708,-18.13 2.074,4.474 -2.57,9.344 -1.244,14.208 v 2.354 c -1.148,1.816 -5.864,3.458 -7.922,4.874 -14.14,9.736 -15.23,14.912 -24.894,26.40001 -6.982,8.3 -15.26,15.5 -22.134,23.932 -11.878,14.576 -27.774,39.38201 -41.434,51.23801 0.79,-11.36 12.096,-43.94801 11.8,-46.44001 0.6,-3.108 1.304,-7.516 4.174,-9.192 0.93,7.21 1.644,14.442 2.54,21.656 1.148,-2.524 1.142,-5.15 2.088,-7.614 8.798,-9.326 16.32,-19.906 24.89,-29.486 4.756,-5.318 10.938,-9.912 15.132,-15.63401 4.15,-5.656 5.632,-12.712 10.296,-18.166 z"
id="path78"
style="stroke-width:2" />
<path
fill="#bf8a24"
d="m 306.53575,171.88167 -6.764,-0.428 1.672,-0.284 c -6.714,-7.61 17.512,-9.466 21.164,-11.206 6.186,-2.944 8.754,-8.358 16.164,-11.038 -2.502,2.67 -10.852,4.99 -2.406,7.588 l -0.286,0.044 c 2.342,0.576 6.822,-0.49 7.562,0.282 11.012,-0.444 21.382,3.234 32.396,2.412 -3.822,-2.582 -9.28,-3.286 -13.692,-4.562 l 0.166,-0.49 c 4.176,-1.344 9.568,0.502 13.526,-1.328 2.99,-0.914 6.34,-0.822 9.44,-1.264 43.72,19.62 46.344,31.682 19.526,73.22601 v 0 c -1.554,2.762 -3.848,7.304 -4.686,10.42 l -0.256,0.984 -0.8,0.356 c -0.148,-6.828 6.032,-14.334 5.742,-19.654 3.41,-15.986 -69.354,5.438 -83.98,12.018 -112.918,50.79001 -146.822,194.80204 -68.622,289.88605 2.912,3.538 9.012,12.78601 14.01,12.81601 5.634,0.72 11.242,1.612 16.884,2.268 -0.202,-4.49 -5.588,-11.15401 -7.948,-15.01601 l 0.744,-0.738 c 0.012,-2.102 -1.516,-3.748 -1.268,-5.77 l 0.892,-0.308 c 1.028,2.482 1.052,5.254 3.65,6.816 1.536,3.252 4.578,6.77601 6.57,9.84601 4.044,-3.966 8.118,-7.76801 12.466,-11.40401 1.258,-0.768 2.186,-1.952 3.172,-3.032 1.292,-8.566 1.428,-17.722 1.922,-26.378 -0.138,-1.118 -0.616,-2.868 -0.238,-3.908 l 1.168,0.966 -0.246,-0.612 -0.924,0.544 1.134,-0.23 c 3.66,6.196 9.036,11.464 13.456,17.124 20.682,-19.848 -7.462,-45.92001 -22.146,-59.30801 8.322,2.714 22.978,21.546 26.672,29.42201 2.368,5.048 2.81,14.832 4.236,17.488 3.938,-9.238 -6.242,-21.60201 -4.594,-23.16201 6.228,12.53801 9.19,23.92001 0,35.56001 -11.034,9.136 -29.284,21.156 -36.122,33.99601 -15.95,29.946 -3.004,58.48801 7.948,85.92401 1.766,3.338 5.028,8.098 5.668,11.75001 h -1.106 l -7.45,-10.00201 c -1.728,-2.178 -3.5,-4.33 -5.016,-6.664 -6.324,-4.728 -13.836,-10.324 -21.092,-13.49 -1.626,-0.89 -3.196,-1.934 -4.78,-2.904 -1.312,-1.568 -4.878,-2.91 -6.762,-3.614 -4.274,-4.488 -9.078,-8.416 -13.794,-12.424 -3.644,-3.258 -7.338,-6.40601 -11.126,-9.49601 -9.516,-10.912 -20.848,-17.964 -34.05,-23.62 -3.398,0.208 -6.702,-1.566 -10.05,-2.2 -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 c -1.778,-0.832 -2.898,-1.432 -3.716,-3.304 l 1.262,-2.344 h -1.262 c -2.998,-1.264 -4.654,-5.114 -7.29,-7.02 -3.114,-2.442 -5.858,-6.428 -8.34,-9.526 -7.37,-9.20401 15.16,1.224 16.892,1.472 -1.776,-4.28401 -4.174,-7.85601 -6.946,-11.55201 v 0 c -1.186,-3.19 -1.29,-6.316 -4.994,-7.248 0.668,0.008 0.234,0.036 1.274,-0.272 l -0.462,-1.048 c -0.872,-0.626 -1.716,-1.272 -2.532,-1.97 -2.314,-1.318 -4.576,-1.42 -7.188,-1.558 l 0.348,-0.398 c -4.896,-4.894 -10.688,-6.678 -13.068,-13.884 -0.332,-1.336 -0.206,-2.176 0,-3.506 -1.728,-2.562 -3.144,-5.188 -4.552,-7.934 6.396,4.284 12.98,7.948 19.826,11.44 -2.314,-2.75 -5.832,-4.474 -7.89,-7.506 2.538,0.37 3.676,2.38 5.976,3.28 l 0.342,-0.572 c -0.624,-1.612 -1.632,-2.87 -2.66,-4.248 -3.542,-4.31 -7.944,-7.966 -11.042,-12.63001 -3.934,-4.148 5.086,0.086 6.686,0.158 l 0.092,-0.576 c -1.518,-2.204 -4.56,-4.154 -6.672,-5.856 l -0.106,-0.944 c -3.076,-1.918 -6.968,-4.214 -8.18,-7.788 l 0.58,-0.476 c 2.488,0.156 4.342,1.274 6.51,2.394 1.374,-7.17 -12.154,-7.824 -6.644,-16.822 -1.502,-3.55 -4.188,-6.62 -5.696,-10.326 1.32,0.836 2.69,1.574 4.06,2.326 3.578,-1.614 1.146,-5.134 0.85,-8.024 l 0.786,-0.856 -5.696,-5.592 v -6.18601 c 1.882,1.082 3.774,2.134 5.696,3.148 2.812,-0.066 -2.302,-7.952 -2.684,-9.412 -2.64,-10.138 -2.074,-19.934 1.048,-30.034 3.832,5.794 5.078,12.906 9.37,18.494 0.712,-12.252 -3.732,-16.226 -6.272,-27.338 0.024,1.614 -0.016,2.56 -0.998,3.888 l -1.026,0.056 c -4.328,-4.398 1.136,-23.06401 2.024,-29.02001 0.876,-1.352 0.326,-3.882 1.568,-4.852 l 0.152,2.372 c 1.97,-6.784 0.63,-13.124 1.634,-19.682 0.592,-3.874 3.912,-9.128 5.378,-12.93801 1.064,3.29801 2.95,26.50601 5.008,35.10001 0.6,-13.1 1.002,-26.334 0.64,-39.44401 1.256,-2.66 2.634,-4.674 4.96,-6.498 1.274,-3.458 -0.992,-8.336 1.82,-11.414 1.332,2.548 0.968,5.34 1.658,8.056 l 0.172,0.658 c 2.028,-7.658 5.626,-15.308 9.904,-21.966 -0.606,5.264 -0.152,10.744 0,16.034 0.094,2.884 0.062,5.748 0,8.632 2.508,-3.846 4.092,-8.608 6.946,-12.09 l 0.804,-0.272 c 3.592,-4.722 6.91,-9.126 10.092,-14.184 1.592,-2.504 3.106,-5.054 5.056,-7.3 1.254,-1.746 2.48,-3.488 3.62,-5.31 -4.986,0.096 -6.758,0.72 -6.442,-4.89801 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 0.074,-2.436 3.196,-4.674 5.056,-5.82 1.996,-2.358 2.592,-6.384 6.472,-5.164 5.168,-5.012 8.8,-14.116 16.818,-14.858 0.326,-3.532 2.758,-15.804 7.368,-15.872 l 2.28,3.718 v 2.082 0 c 2.592,-0.354 13.382,-3.338 15.272,-4.588 4.386,-0.624 8.88,-2.052 13.11,-3.378 1.588,-0.816 3.074,-2.294 4.418,-3.494 9.014,-8.06201 20.48,-8.68001 27.53,-13.56001 l 0.042,-1.276 h -2.702 c -7.65,-3.338 -12.068,0.834 -18.448,-0.768 11.644,-3.204 15.88,-5.512 29.284,-7.922 z"
id="path79"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 154.48175,356.6817 c 1.552,0.2 3.084,0.076 4.642,0 -0.404,2.63801 -0.692,5.29001 -1.092,7.92601 -1.188,-2.608 -2.544,-5.248 -3.55,-7.92601 z"
id="path80"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 159.12375,442.51972 c 0.384,2.614 0.992,5.194 1.546,7.778 -3.03,-2.766 -6.444,-5.21 -9.65,-7.778 l 0.538,0.054 c 2.192,0.234 4.934,1.556 6.996,1.18 z"
id="path81"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 175.47975,498.19573 c 0.814,1.764 4.086,6.738 0,5.588 -2.314,-1.318 -4.576,-1.42 -7.188,-1.558 l 0.348,-0.398 c 2.21,-2.024 4.874,-1.53 6.84,-3.632 z"
id="path82"
style="stroke-width:2" />
<path
fill="#ad7214"
d="m 155.57175,466.26772 c 9.084,-1.716 12.038,4.78201 11.562,12.49601 l -0.52,0.134 c -3.542,-4.31 -7.944,-7.966 -11.042,-12.63001 z"
id="path83"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 155.57175,459.04972 c -3.076,-1.918 -6.968,-4.214 -8.18,-7.788 l 0.58,-0.476 c 2.488,0.156 4.342,1.274 6.51,2.394 2.566,1.4 4.326,3.672 6.188,5.87 1.02,1.764 1.71,3.5 2.37,5.424 -2.364,-1.688 -4.912,-4.152 -7.468,-5.424 z"
id="path84"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 180.58775,533.92774 c -3.114,-2.442 -5.858,-6.428 -8.34,-9.526 -7.37,-9.20401 15.16,1.224 16.892,1.472 6.636,13.13 -9.994,0.33 -16.85,-2.24 3.11,3.16 6.322,6.268 8.298,10.294 z"
id="path85"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 266.41175,531.65974 c 5.634,0.72 11.242,1.612 16.884,2.268 -0.584,3.624 -3.86,8.832 -5.208,12.668 -3.562,-5.308 -7.8,-9.892 -11.676,-14.936 z"
id="path86"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 142.14175,426.03172 c 1.32,0.836 2.69,1.574 4.06,2.326 4.29,3.432 12.174,7.82 12.862,13.616 l 0.06,0.546 -0.57,1.234 c -2.062,0.376 -4.804,-0.946 -6.996,-1.18 l -0.538,-0.054 c -1,-2.096 -2.014,-4.15 -3.182,-6.162 -1.502,-3.55 -4.188,-6.62 -5.696,-10.326 z"
id="path87"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 142.14175,407.69971 c 1.882,1.082 3.774,2.134 5.696,3.148 3.018,1.372 5.362,4.13001 7.734,6.39601 0.206,2.976 0.198,5.812 0,8.788 -2.638,-2.122 -5.196,-4.312 -7.734,-6.554 l -5.696,-5.592 z"
id="path88"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 155.57175,484.43773 c 2.938,2.218 18.9,12.614 19.908,13.758 -1.966,2.102 -4.63,1.608 -6.84,3.632 -4.896,-4.894 -10.688,-6.678 -13.068,-13.884 -0.332,-1.336 -0.206,-2.176 0,-3.506 z"
id="path89"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 303.49575,487.94373 c -0.138,-1.118 -0.616,-2.868 -0.238,-3.908 l 1.168,0.966 -0.246,-0.612 -0.924,0.544 1.134,-0.23 c 3.66,6.196 9.036,11.464 13.456,17.124 -2.234,2.422 -5.066,4.484 -7.648,6.516 -1.722,-5.352 -6.16,-14.438 -4.026,-19.786 l -0.84,-0.608 c -0.8,1.028 -0.922,2.05 -1.224,3.294 z"
id="path90"
style="stroke-width:2" />
<path
fill="#f1be39"
d="m 343.64175,156.83967 c 11.012,-0.444 21.382,3.234 32.396,2.412 v 0 c 2.758,1.782 6.394,1.874 9.44,3.152 -10.682,1.228 -39.754,-2.68 -41.606,-1.904 0.806,1.616 2.88,2.336 4.224,3.502 l -1.41,0.542 0.34,0.15 -1.298,-0.124 c -4.908,-6.008 -9.214,-5.39 -10.248,-6.48 2.774,-0.232 5.512,-0.324 8.162,-1.25 z"
id="path91"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 376.03775,152.87167 c 2.99,-0.914 6.34,-0.822 9.44,-1.264 43.72,19.62 46.344,31.682 19.526,73.22601 v 0 c 5.832,-22.874 34.842,-43.05801 -2.732,-64.07601 -11.18,-6.254 -18.164,-10.16 -31.452,-6.352 l -0.424,1.2 -0.404,-0.834 c 3.842,4.244 26.77,7.59 30.22,14.342 -1.308,0.37 -18.904,-9.996 -23.724,-10.5 l -0.45,0.638 v 0 c -3.822,-2.582 -9.28,-3.286 -13.692,-4.562 l 0.166,-0.49 c 4.176,-1.344 9.568,0.502 13.526,-1.328 z"
id="path92"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 168.63975,291.53969 c 1.274,-3.458 -0.992,-8.336 1.82,-11.414 1.332,2.548 0.968,5.34 1.658,8.056 l 0.172,0.658 c 2.774,10.994 2.712,19.95201 -1.444,30.43201 -1.604,-9.654 -3.796,-17.92201 -2.206,-27.73201 z"
id="path93"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 149.29975,337.4817 c 0.876,-1.352 0.326,-3.882 1.568,-4.852 l 0.152,2.372 c 1.894,5.472 9.814,16.574 8.104,21.68 -1.558,0.076 -3.09,0.2 -4.642,0 -1.126,-2.77 -2.134,-5.716 -3.462,-8.39 -1.878,5.094 -2.658,8.81 -1.72,14.26601 0.024,1.614 -0.016,2.56 -0.998,3.888 l -1.026,0.056 c -4.328,-4.398 1.136,-23.06401 2.024,-29.02001 z"
id="path94"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 306.53575,171.88167 -6.764,-0.428 1.672,-0.284 c -6.714,-7.61 17.512,-9.466 21.164,-11.206 6.186,-2.944 8.754,-8.358 16.164,-11.038 -2.502,2.67 -10.852,4.99 -2.406,7.588 l -0.286,0.044 c 2.342,0.576 6.822,-0.49 7.562,0.282 -2.65,0.926 -5.388,1.018 -8.162,1.25 1.034,1.09 5.34,0.472 10.248,6.48 -3.348,-0.918 -27.976,0.078 -32.714,1.348 4.33,2.232 9.916,1.048 14.594,3.258 l 0.012,0.634 c -3.474,2.758 -16.412,2.3 -21.084,2.072 z"
id="path95"
style="stroke-width:2" />
<path
fill="#ad7214"
d="m 187.87775,540.94774 c 14.452,-1.578 18.17,9.438 25.354,17.744 17.95,20.75601 34.99,32.52001 57.314,46.64401 2.982,1.888 11.55,9.15 14.164,9.758 -0.954,-3.75 -7.964,-27.508 -9.222,-29.136 -2.72,-3.514 -11.288,-7.96801 -15.268,-11.09401 -12.18,-9.558 -46.938,-41.988 -52.316,-57.27201 l 0.808,-0.238 c 9.448,21.46801 48.068,54.83801 66.636,67.04602 1.412,2.178 10.994,29.386 10.588,32.432 -6.324,-4.728 -13.836,-10.324 -21.092,-13.49 -1.626,-0.89 -3.196,-1.934 -4.78,-2.904 -1.312,-1.568 -4.878,-2.91 -6.762,-3.614 -4.274,-4.488 -9.078,-8.416 -13.794,-12.424 -3.644,-3.258 -7.338,-6.40601 -11.126,-9.49601 -9.516,-10.912 -20.848,-17.964 -34.05,-23.62 -3.398,0.208 -6.702,-1.566 -10.05,-2.2 -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 c -1.778,-0.832 -2.898,-1.432 -3.716,-3.304 l 1.262,-2.344 z"
id="path96"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 189.13975,540.94774 c 5.534,2.624 11.97,2.904 15.952,8.136 -3.688,-0.196 -7.236,-1.452 -10.76,-2.488 h -2.738 c -1.778,-0.832 -2.898,-1.432 -3.716,-3.304 z"
id="path97"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 184.28175,549.08374 c -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 h 2.738 c 3.524,1.036 7.072,2.292 10.76,2.488 1.886,2.01 3.24,4.586 4.692,6.922 -3.318,-1.236 -12.546,-5.238 -15.452,-4.722 v 0 c -3.398,0.208 -6.702,-1.566 -10.05,-2.2 z"
id="path98"
style="stroke-width:2" />
<path
fill="#e7aa1f"
d="m 184.28175,549.08374 c -3.33,-5.012 3.684,-2.256 6.652,-2.44 l 0.66,-0.048 h 2.738 c -4.344,0.788 -4.744,0.478 -1.17,2.97 l -0.606,-0.004 c -4.844,0.006 -0.282,1.608 1.776,1.722 v 0 c -3.398,0.208 -6.702,-1.566 -10.05,-2.2 z"
id="path99"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 228.38175,216.93968 c 0.326,-3.532 2.758,-15.804 7.368,-15.872 l 2.28,3.718 v 2.082 0 c -6.518,12.316 13.27,-2.088 15.158,-2.352 -0.618,2.432 -27.42,25.384 -31.64,31.524 -3.73,5.426 -11.42,18.06801 -16.456,21.65401 1.254,-1.746 2.48,-3.488 3.62,-5.31 -4.986,0.096 -6.758,0.72 -6.442,-4.89801 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 0.074,-2.436 3.196,-4.674 5.056,-5.82 1.996,-2.358 2.592,-6.384 6.472,-5.164 5.168,-5.012 8.8,-14.116 16.818,-14.858 z"
id="path100"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 232.69375,222.27368 v 0 c -2.516,5.136 -7.8,8.384 -11.258,12.894 0.908,-3.178 1.606,-7.628 3.46,-10.334 2.71,0.164 5.344,-1.512 7.798,-2.56 z"
id="path101"
style="stroke-width:2" />
<path
fill="#e4c267"
d="m 205.09175,236.96168 c 1.996,-2.358 2.592,-6.384 6.472,-5.164 -1.882,3.976 -3.154,7.958 -2.26,12.41 l 0.746,0.966 c 1.808,0.074 2.558,-0.808 4.2,-1.294 -0.568,2.526 -3.898,6.34801 -5.538,8.50401 -4.986,0.096 -6.758,0.72 -6.442,-4.89801 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 0.074,-2.436 3.196,-4.674 5.056,-5.82 z"
id="path102"
style="stroke-width:2" />
<path
fill="#d6991c"
d="m 200.03575,242.78168 c 0.074,-2.436 3.196,-4.674 5.056,-5.82 -1.032,3.436 -2.298,6.974 -2.822,10.524 v 0 c -0.608,-1.734 -1.11,-3.236 -2.234,-4.704 z"
id="path103"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 228.38175,216.93968 c 0.326,-3.532 2.758,-15.804 7.368,-15.872 l 2.28,3.718 v 2.082 c -1.486,1.796 -3.142,3.526 -3.43,5.944 4.566,-0.902 8.72,-2.206 13.04,-3.914 -4.882,4.584 -9.786,9.102 -14.946,13.376 v 0 c -2.454,1.048 -5.088,2.724 -7.798,2.56 0.764,-2.614 2.36,-5.384 3.486,-7.894 z"
id="path104"
style="stroke-width:2" />
<path
fill="#fade6b"
d="m 358.50775,173.44367 c 18.416,-4.38 53.464,-10.342 55.298,16.884 -24.86,0.57 -35.762,0.938 -60.484,4.82201 l -0.202,-0.514 c 1.278,-0.93 3.428,-0.886 4.184,-1.712 6.046,-6.58801 1.738,-6.33201 2.402,-12.86401 0.52,-5.102 6.456,-5.5 -0.302,-6.478 z"
id="path105"
style="stroke-width:2" />
<defs
id="defs106">
<linearGradient
id="gradient_7"
gradientUnits="userSpaceOnUse"
x1="141.16791"
y1="268.56354"
x2="265.50784"
y2="226.48077"
gradientTransform="matrix(2,0,0,2.0000004,-111.74825,-110.67438)">
<stop
offset="0"
stop-color="#E1AF37"
id="stop105" />
<stop
offset="1"
stop-color="#FCDE74"
id="stop106" />
</linearGradient>
</defs>
<path
fill="url(#gradient_7)"
d="m 208.71175,517.35373 c -86.018,-118.12402 -12.156,-301.82605 129.714,-339.49006 6.44,-1.71 13.438,-3.836 20.082,-4.42 l 0.896,0.138 c 6.758,0.978 0.822,1.376 0.302,6.478 -0.664,6.532 3.644,6.276 -2.402,12.86401 -0.756,0.826 -2.906,0.782 -4.184,1.712 l 0.202,0.514 c -12.89,3.57 -25.456,7.312 -37.754,12.642 -137.6,59.63401 -168.028,233.46204 -63.62,337.58006 7.44,7.418 16.184,13.6 23.4,21.124 0.094,5.944 0.338,11.96801 0,17.90401 -18.568,-12.20801 -57.188,-45.57801 -66.636,-67.04602 z"
id="path106"
style="fill:url(#gradient_7);stroke-width:2" />
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -1,38 +1,30 @@
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" integrity="sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju1MVsGrX5xXxAvs/HgeFs" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/js-md5@0.8.3/src/md5.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" integrity="sha384-8hHkOkbWN1TLWwet/jpbJ0zbx3FJDeYJgQ8dX1mRrv/vfCfHCqFSFZYCgaMML3z9" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js" integrity="sha384-u4eJN1VWrTf/FnYYQJo2kqJyVxEQf5UmWY4iUcNAoLenOEtEuCkfwc5bKvZOWBi5" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/tableexport.jquery.plugin@1.30.0/tableExport.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/tableexport.jquery.plugin@1.28.0/tableExport.min.js" integrity="sha384-1Rz4Kz/y1rSWw+ZsjTcxB684XgofbO8iizY+UFIzCwFeQ+QUyhBNWBMh/STOyomI" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js" integrity="sha384-IazMVNyYoUNx6357fWJoqtHYUWWCNHIXxFVtbpVgvImQNWuRP2WbHPaIb3QF8j97" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.2/dist/bootstrap-table.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js" integrity="sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/bootstrap-table.min.js" integrity="sha384-GVLHfbEvuGA/RFiQ3MK2ClEJkWYJXABg55t9LpoDPZFGIsSq8xhFlQydm5poV2jW" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.2/dist/extensions/export/bootstrap-table-export.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.2/dist/extensions/resizable/bootstrap-table-resizable.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.2/dist/extensions/filter-control/bootstrap-table-filter-control.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/extensions/export/bootstrap-table-export.min.js" integrity="sha384-g9OAB1Moamcy8+l1Q/tajHlMf6NTkS79ehKLTYbA80aQRbRhFCjrSuezv+FE2Kwe" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/extensions/resizable/bootstrap-table-resizable.js" integrity="sha384-wd8Vc6Febikdnsnk9vthRWRvMwffw246vhqiqNO3aSNe1maTEA07Vh3zAQiSyDji" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/extensions/filter-control/bootstrap-table-filter-control.js" integrity="sha384-NIqcjpr/3eZI1iNzz7hgT5rgp70qFUzkZffeCgVva9gi80B5vqcm7gn+8QvlWxko" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.umd.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js" integrity="sha384-F/bZzf7p3Joyp5psL90p/p89AZJsndkSoGwRpXcZhleCWhd8SnRuoYo4d0yirjJp" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.10.0/build/highlight.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script>
async function copyToClipboard(text, button) {
if (navigator.clipboard === undefined) {
const input = document.createElement("textarea");
input.innerHTML = text;
document.body.appendChild(input);
input.select();
document.execCommand("copy");
document.body.removeChild(input);
} else {
await navigator.clipboard.writeText(text);
}
button.html("<i class=\"bi bi-clipboard-check\"></i> copied");
setTimeout(()=> {
button.html("<i class=\"bi bi-clipboard\"></i> copy");
await navigator.clipboard.writeText(text);
button.innerHTML = "<i class=\"bi bi-clipboard-check\"></i> copied";
setTimeout(_ => {
button.innerHTML = "<i class=\"bi bi-clipboard\"></i> copy";
}, 2000);
}
@ -73,6 +65,47 @@
.join("<br>");
}
function makeRequest(url, params, onSuccess, onFailure) {
const requestParams = {
method: params.method,
body: params.json ? JSON.stringify(params.json) : params.json,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
};
if (params.query) {
const query = new URLSearchParams(params.query);
url += `?${query.toString()}`;
}
const convert = params.convert ?? (response => response.text());
return fetch(url, requestParams)
.then(response => {
if (response.ok) {
return convert(response);
} else {
const error = new Error("Network request error");
error.status = response.status;
error.statusText = response.statusText;
return response.text().then(text => {
error.text = text;
throw error;
});
}
})
.then(data => onSuccess && onSuccess(data))
.catch(error => onFailure && onFailure(error));
}
function ready(fn) {
if (document.readyState === "complete" || document.readyState === "interactive") {
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
function safe(string) {
return String(string)
.replace(/&/g, "&amp;")
@ -86,7 +119,9 @@
const element = document.createElement("a");
element.href = url;
element.innerText = text;
if (title) element.title = title;
if (title) {
element.title = title;
}
return element;
}

View File

@ -1,17 +1,15 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" integrity="sha384-4LISF5TTJX/fLmGSxO53rV4miRxdg84mZsxmO8Rx5jGtp/LbrixFETvWa5a6sESd" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/bootstrap-table.min.css" integrity="sha384-sN3NwxbjH33ZidqZnPmX+nQ5IF+LoiI7HvZSoZj5wGacmu0/q4RJfsN0xqN+LIa5" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.2/dist/bootstrap-table.min.css" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" integrity="sha384-1sLxvR8mXzjhvFY9f8mzXl97DNLepeZ0PnRiMMdm/rQsKjsrPZPJxYle2wwT2PMg" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/extensions/filter-control/bootstrap-table-filter-control.css" integrity="sha384-4Glx18jZ0Un+yDG6KUpYJ/af8hkssJ02jRASuFv23gfCl0mTXaVMPI9cB4cn3GvE" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.23.2/dist/extensions/filter-control/bootstrap-table-filter-control.css" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.3.2/dist/cosmo/bootstrap.min.css" integrity="sha384-RfV5VNj9uqyOdZbN0hFNmoq56291KK2Y4iKhoRAbcfBfjYlpasjxK6TefPjxiAiN" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.3.3/dist/cosmo/bootstrap.min.css" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.css" integrity="sha384-zLkQsiLfAQqGeIJeKLC+rcCR1YoYaQFLCL7cLDUoKE1ajKJzySpjzWGfYS2vjSG+" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github.min.css" integrity="sha384-eFTL69TLRZTkNfYZOLM+G04821K1qZao/4QLJbet1pP4tcF+fdXq/9CdqAbWRl/L" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.10.0/build/styles/github.min.css" crossorigin="anonymous" type="text/css">
<style>
.pre-scrollable {

View File

@ -1,6 +1,6 @@
# AUTOMATICALLY GENERATED by `shtab`
_shtab_ahriman_subparsers=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-changes' 'package-changes-remove' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
_shtab_ahriman_subparsers=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-changes' 'package-changes-remove' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '-V' '--version' '--wait-timeout')
_shtab_ahriman_aur_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
@ -10,9 +10,9 @@ _shtab_ahriman_help_option_strings=('-h' '--help')
_shtab_ahriman_help_updates_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_help_version_option_strings=('-h' '--help')
_shtab_ahriman_version_option_strings=('-h' '--help')
_shtab_ahriman_package_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_package_update_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_package_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_package_update_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_package_changes_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_package_changes_remove_option_strings=('-h' '--help')
_shtab_ahriman_package_remove_option_strings=('-h' '--help')
@ -27,12 +27,12 @@ _shtab_ahriman_patch_list_option_strings=('-h' '--help' '-e' '--exit-code' '-v'
_shtab_ahriman_patch_remove_option_strings=('-h' '--help' '-v' '--variable')
_shtab_ahriman_patch_set_add_option_strings=('-h' '--help' '-t' '--track')
_shtab_ahriman_repo_backup_option_strings=('-h' '--help')
_shtab_ahriman_repo_check_option_strings=('-h' '--help' '--changes' '--no-changes' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_check_option_strings=('-h' '--help' '--changes' '--no-changes' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_repo_check_option_strings=('-h' '--help' '--changes' '--no-changes' '--check-files' '--no-check-files' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_check_option_strings=('-h' '--help' '--changes' '--no-changes' '--check-files' '--no-check-files' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_repo_create_keyring_option_strings=('-h' '--help')
_shtab_ahriman_repo_create_mirrorlist_option_strings=('-h' '--help')
_shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_repo_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username')
_shtab_ahriman_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username')
_shtab_ahriman_repo_remove_unknown_option_strings=('-h' '--help' '--dry-run')
@ -42,13 +42,14 @@ _shtab_ahriman_report_option_strings=('-h' '--help')
_shtab_ahriman_repo_restore_option_strings=('-h' '--help' '-o' '--output')
_shtab_ahriman_repo_sign_option_strings=('-h' '--help')
_shtab_ahriman_sign_option_strings=('-h' '--help')
_shtab_ahriman_repo_statistics_option_strings=('-h' '--help' '--chart' '-e' '--event' '--from-date' '--limit' '--offset' '--to-date')
_shtab_ahriman_repo_status_update_option_strings=('-h' '--help' '-s' '--status')
_shtab_ahriman_repo_sync_option_strings=('-h' '--help')
_shtab_ahriman_sync_option_strings=('-h' '--help')
_shtab_ahriman_repo_tree_option_strings=('-h' '--help' '-p' '--partitions')
_shtab_ahriman_repo_triggers_option_strings=('-h' '--help')
_shtab_ahriman_repo_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_repo_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_service_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
_shtab_ahriman_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
_shtab_ahriman_repo_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
@ -78,7 +79,7 @@ _shtab_ahriman_web_option_strings=('-h' '--help')
_shtab_ahriman_pos_0_choices=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-changes' 'package-changes-remove' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
_shtab_ahriman_pos_0_choices=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-changes' 'package-changes-remove' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
_shtab_ahriman___log_handler_choices=('console' 'syslog' 'journald')
_shtab_ahriman_aur_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
_shtab_ahriman_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
@ -100,6 +101,8 @@ _shtab_ahriman_repo_rebuild__s_choices=('unknown' 'pending' 'building' 'failed'
_shtab_ahriman_repo_rebuild___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_rebuild__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_rebuild___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_statistics__e_choices=('package-outdated' 'package-removed' 'package-update-failed' 'package-updated')
_shtab_ahriman_repo_statistics___event_choices=('package-outdated' 'package-removed' 'package-update-failed' 'package-updated')
_shtab_ahriman_repo_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_service_setup___sign_target_choices=('disabled' 'packages' 'repository')
@ -153,6 +156,8 @@ _shtab_ahriman_version___help_nargs=0
_shtab_ahriman_package_add_pos_0_nargs=+
_shtab_ahriman_package_add__h_nargs=0
_shtab_ahriman_package_add___help_nargs=0
_shtab_ahriman_package_add___changes_nargs=0
_shtab_ahriman_package_add___no_changes_nargs=0
_shtab_ahriman_package_add___dependencies_nargs=0
_shtab_ahriman_package_add___no_dependencies_nargs=0
_shtab_ahriman_package_add__e_nargs=0
@ -166,6 +171,8 @@ _shtab_ahriman_package_add___refresh_nargs=0
_shtab_ahriman_add_pos_0_nargs=+
_shtab_ahriman_add__h_nargs=0
_shtab_ahriman_add___help_nargs=0
_shtab_ahriman_add___changes_nargs=0
_shtab_ahriman_add___no_changes_nargs=0
_shtab_ahriman_add___dependencies_nargs=0
_shtab_ahriman_add___no_dependencies_nargs=0
_shtab_ahriman_add__e_nargs=0
@ -179,6 +186,8 @@ _shtab_ahriman_add___refresh_nargs=0
_shtab_ahriman_package_update_pos_0_nargs=+
_shtab_ahriman_package_update__h_nargs=0
_shtab_ahriman_package_update___help_nargs=0
_shtab_ahriman_package_update___changes_nargs=0
_shtab_ahriman_package_update___no_changes_nargs=0
_shtab_ahriman_package_update___dependencies_nargs=0
_shtab_ahriman_package_update___no_dependencies_nargs=0
_shtab_ahriman_package_update__e_nargs=0
@ -243,6 +252,8 @@ _shtab_ahriman_repo_check__h_nargs=0
_shtab_ahriman_repo_check___help_nargs=0
_shtab_ahriman_repo_check___changes_nargs=0
_shtab_ahriman_repo_check___no_changes_nargs=0
_shtab_ahriman_repo_check___check_files_nargs=0
_shtab_ahriman_repo_check___no_check_files_nargs=0
_shtab_ahriman_repo_check__e_nargs=0
_shtab_ahriman_repo_check___exit_code_nargs=0
_shtab_ahriman_repo_check___vcs_nargs=0
@ -254,6 +265,8 @@ _shtab_ahriman_check__h_nargs=0
_shtab_ahriman_check___help_nargs=0
_shtab_ahriman_check___changes_nargs=0
_shtab_ahriman_check___no_changes_nargs=0
_shtab_ahriman_check___check_files_nargs=0
_shtab_ahriman_check___no_check_files_nargs=0
_shtab_ahriman_check__e_nargs=0
_shtab_ahriman_check___exit_code_nargs=0
_shtab_ahriman_check___vcs_nargs=0
@ -270,6 +283,8 @@ _shtab_ahriman_repo_daemon___aur_nargs=0
_shtab_ahriman_repo_daemon___no_aur_nargs=0
_shtab_ahriman_repo_daemon___changes_nargs=0
_shtab_ahriman_repo_daemon___no_changes_nargs=0
_shtab_ahriman_repo_daemon___check_files_nargs=0
_shtab_ahriman_repo_daemon___no_check_files_nargs=0
_shtab_ahriman_repo_daemon___dependencies_nargs=0
_shtab_ahriman_repo_daemon___no_dependencies_nargs=0
_shtab_ahriman_repo_daemon___dry_run_nargs=0
@ -291,6 +306,8 @@ _shtab_ahriman_daemon___aur_nargs=0
_shtab_ahriman_daemon___no_aur_nargs=0
_shtab_ahriman_daemon___changes_nargs=0
_shtab_ahriman_daemon___no_changes_nargs=0
_shtab_ahriman_daemon___check_files_nargs=0
_shtab_ahriman_daemon___no_check_files_nargs=0
_shtab_ahriman_daemon___dependencies_nargs=0
_shtab_ahriman_daemon___no_dependencies_nargs=0
_shtab_ahriman_daemon___dry_run_nargs=0
@ -340,6 +357,8 @@ _shtab_ahriman_repo_sign___help_nargs=0
_shtab_ahriman_sign_pos_0_nargs=*
_shtab_ahriman_sign__h_nargs=0
_shtab_ahriman_sign___help_nargs=0
_shtab_ahriman_repo_statistics__h_nargs=0
_shtab_ahriman_repo_statistics___help_nargs=0
_shtab_ahriman_repo_status_update__h_nargs=0
_shtab_ahriman_repo_status_update___help_nargs=0
_shtab_ahriman_repo_sync__h_nargs=0
@ -358,6 +377,8 @@ _shtab_ahriman_repo_update___aur_nargs=0
_shtab_ahriman_repo_update___no_aur_nargs=0
_shtab_ahriman_repo_update___changes_nargs=0
_shtab_ahriman_repo_update___no_changes_nargs=0
_shtab_ahriman_repo_update___check_files_nargs=0
_shtab_ahriman_repo_update___no_check_files_nargs=0
_shtab_ahriman_repo_update___dependencies_nargs=0
_shtab_ahriman_repo_update___no_dependencies_nargs=0
_shtab_ahriman_repo_update___dry_run_nargs=0
@ -380,6 +401,8 @@ _shtab_ahriman_update___aur_nargs=0
_shtab_ahriman_update___no_aur_nargs=0
_shtab_ahriman_update___changes_nargs=0
_shtab_ahriman_update___no_changes_nargs=0
_shtab_ahriman_update___check_files_nargs=0
_shtab_ahriman_update___no_check_files_nargs=0
_shtab_ahriman_update___dependencies_nargs=0
_shtab_ahriman_update___no_dependencies_nargs=0
_shtab_ahriman_update___dry_run_nargs=0
@ -584,7 +607,7 @@ _set_new_action() {
current_action_nargs=1
fi
current_action_args_start_index=$(( $word_index + 1 ))
current_action_args_start_index=$(( $word_index + 1 - $pos_only ))
current_action_is_positional=$2
}
@ -611,6 +634,7 @@ _shtab_ahriman() {
local prefix=_shtab_ahriman
local word_index=0
local pos_only=0 # "--" delimeter not encountered yet
_set_parser_defaults
word_index=1
@ -619,26 +643,30 @@ _shtab_ahriman() {
while [ $word_index -ne $COMP_CWORD ]; do
local this_word="${COMP_WORDS[$word_index]}"
if [[ -n $sub_parsers && " ${sub_parsers[@]} " == *" ${this_word} "* ]]; then
# valid subcommand: add it to the prefix & reset the current action
prefix="${prefix}_$(_shtab_replace_nonword $this_word)"
_set_parser_defaults
fi
if [[ $pos_only = 1 || " $this_word " != " -- " ]]; then
if [[ -n $sub_parsers && " ${sub_parsers[@]} " == *" ${this_word} "* ]]; then
# valid subcommand: add it to the prefix & reset the current action
prefix="${prefix}_$(_shtab_replace_nonword $this_word)"
_set_parser_defaults
fi
if [[ " ${current_option_strings[@]} " == *" ${this_word} "* ]]; then
# a new action should be acquired (due to recognised option string or
# no more input expected from current action);
# the next positional action can fill in here
_set_new_action $this_word false
fi
if [[ " ${current_option_strings[@]} " == *" ${this_word} "* ]]; then
# a new action should be acquired (due to recognised option string or
# no more input expected from current action);
# the next positional action can fill in here
_set_new_action $this_word false
fi
if [[ "$current_action_nargs" != "*" ]] && \
[[ "$current_action_nargs" != "+" ]] && \
[[ "$current_action_nargs" != *"..." ]] && \
(( $word_index + 1 - $current_action_args_start_index >= \
$current_action_nargs )); then
$current_action_is_positional && let "completed_positional_actions += 1"
_set_new_action "pos_${completed_positional_actions}" true
if [[ "$current_action_nargs" != "*" ]] && \
[[ "$current_action_nargs" != "+" ]] && \
[[ "$current_action_nargs" != *"..." ]] && \
(( $word_index + 1 - $current_action_args_start_index - $pos_only >= \
$current_action_nargs )); then
$current_action_is_positional && let "completed_positional_actions += 1"
_set_new_action "pos_${completed_positional_actions}" true
fi
else
pos_only=1 # "--" delimeter encountered
fi
let "word_index+=1"
@ -646,7 +674,7 @@ _shtab_ahriman() {
# Generate the completions
if [[ "${completing_word}" == -* ]]; then
if [[ $pos_only = 0 && "${completing_word}" == -* ]]; then
# optional argument started: use option strings
COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") )
else

View File

@ -1,9 +1,9 @@
.TH AHRIMAN "1" "2024\-02\-09" "ahriman" "Generated Python Manual"
.TH AHRIMAN "1" "2024\-09\-23" "ahriman" "Generated Python Manual"
.SH NAME
ahriman
.SH SYNOPSIS
.B ahriman
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {aur-search,search,help-commands-unsafe,help,help-updates,help-version,version,package-add,add,package-update,package-changes,package-changes-remove,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-repositories,service-run,run,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,service-tree-migrate,user-add,user-list,user-remove,web} ...
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {aur-search,search,help-commands-unsafe,help,help-updates,help-version,version,package-add,add,package-update,package-changes,package-changes-remove,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-statistics,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-repositories,service-run,run,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,service-tree-migrate,user-add,user-list,user-remove,web} ...
.SH DESCRIPTION
ArcH linux ReposItory MANager
@ -134,6 +134,9 @@ restore repository data
\fBahriman\fR \fI\,repo\-sign\/\fR
sign packages
.TP
\fBahriman\fR \fI\,repo\-statistics\/\fR
repository statistics
.TP
\fBahriman\fR \fI\,repo\-status\-update\/\fR
update repository status
.TP
@ -248,7 +251,8 @@ usage: ahriman help\-version [\-h]
print application and its dependencies versions
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
usage: ahriman package\-add [\-h] [\-\-dependencies | \-\-no\-dependencies] [\-e] [\-\-increment | \-\-no\-increment] [\-n] [\-y]
usage: ahriman package\-add [\-h] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies] [\-e]
[\-\-increment | \-\-no\-increment] [\-n] [\-y]
[\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME] [\-v VARIABLE]
package [package ...]
@ -259,6 +263,10 @@ add existing or new package to the build queue
package source (base name, path to local files, remote URL)
.SH OPTIONS \fI\,'ahriman package\-add'\/\fR
.TP
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
calculate changes from the latest known commit if available
.TP
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
process missing package dependencies
@ -391,7 +399,7 @@ PKGBUILD variable or function name. If variable is a function, it must end with
path to file which contains function or variable value. If not set, the value will be read from stdin
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] [package]
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] package
list available patches for the package
@ -447,7 +455,9 @@ backup repository settings and database
path of the output archive
.SH COMMAND \fI\,'ahriman repo\-check'\/\fR
usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-e] [\-\-vcs | \-\-no\-vcs] [\-y] [package ...]
usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files] [\-e] [\-\-vcs | \-\-no\-vcs]
[\-y]
[package ...]
check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual
@ -458,7 +468,11 @@ filter check by package base
.SH OPTIONS \fI\,'ahriman repo\-check'\/\fR
.TP
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
calculate changes from the latest known commit if available. Only applicable in dry run mode
calculate changes from the latest known commit if available
.TP
\fB\-\-check\-files\fR, \fB\-\-no\-check\-files\fR
enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories)
.TP
\fB\-e\fR, \fB\-\-exit\-code\fR
@ -484,9 +498,9 @@ create package which contains list of available mirrors as set by configuration.
.SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR
usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes]
[\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-\-increment | \-\-no\-increment]
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-\-partitions | \-\-no\-partitions]
[\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
[\-\-check\-files | \-\-no\-check\-files] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run]
[\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual]
[\-\-partitions | \-\-no\-partitions] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
start process which periodically will run update process
@ -503,6 +517,10 @@ enable or disable checking for AUR updates
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
calculate changes from the latest known commit if available. Only applicable in dry run mode
.TP
\fB\-\-check\-files\fR, \fB\-\-no\-check\-files\fR
enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories)
.TP
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
process missing package dependencies
@ -614,6 +632,43 @@ usage: ahriman repo\-sign [\-h] [package ...]
\fBpackage\fR
sign only specified packages
.SH COMMAND \fI\,'ahriman repo\-statistics'\/\fR
usage: ahriman repo\-statistics [\-h] [\-\-chart CHART]
[\-e {package\-outdated,package\-removed,package\-update\-failed,package\-updated}]
[\-\-from\-date FROM_DATE] [\-\-limit LIMIT] [\-\-offset OFFSET] [\-\-to\-date TO_DATE]
[package]
fetch repository statistics
.TP
\fBpackage\fR
fetch only events for the specified package
.SH OPTIONS \fI\,'ahriman repo\-statistics'\/\fR
.TP
\fB\-\-chart\fR \fI\,CHART\/\fR
create updates chart and save it to the specified path
.TP
\fB\-e\fR \fI\,{package\-outdated,package\-removed,package\-update\-failed,package\-updated}\/\fR, \fB\-\-event\fR \fI\,{package\-outdated,package\-removed,package\-update\-failed,package\-updated}\/\fR
event type filter
.TP
\fB\-\-from\-date\fR \fI\,FROM_DATE\/\fR
only fetch events which are newer than the date
.TP
\fB\-\-limit\fR \fI\,LIMIT\/\fR
limit response by specified amount of events
.TP
\fB\-\-offset\fR \fI\,OFFSET\/\fR
skip specified amount of events
.TP
\fB\-\-to\-date\fR \fI\,TO_DATE\/\fR
only fetch events which are older than the date
.SH COMMAND \fI\,'ahriman repo\-status\-update'\/\fR
usage: ahriman repo\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}]
@ -649,9 +704,9 @@ run triggers on empty build result as configured by settings
instead of running all triggers as set by configuration, just process specified ones in order of mention
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies]
[\-\-dry\-run] [\-e] [\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local]
[\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files]
[\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-e] [\-\-increment | \-\-no\-increment]
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
[package ...]
check for packages updates and run build process if requested
@ -669,6 +724,10 @@ enable or disable checking for AUR updates
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
calculate changes from the latest known commit if available. Only applicable in dry run mode
.TP
\fB\-\-check\-files\fR, \fB\-\-no\-check\-files\fR
enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories)
.TP
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
process missing package dependencies

View File

@ -48,6 +48,7 @@ _shtab_ahriman_commands() {
"repo-restore:restore settings and database"
"repo-setup:create initial service configuration, requires root"
"repo-sign:(re-)sign packages and repository database according to current settings"
"repo-statistics:fetch repository statistics"
"repo-status-update:update repository status on the status page"
"repo-sync:sync repository files to remote server according to current settings"
"repo-tree:dump repository tree based on packages dependencies"
@ -86,7 +87,7 @@ _shtab_ahriman_options=(
{-a,--architecture}"[filter by target architecture (default\: None)]:architecture:"
{-c,--configuration}"[configuration path (default\: \/etc\/ahriman.ini)]:configuration:"
"--force[force run, remove file lock (default\: False)]"
{-l,--lock}"[lock file (default\: \/tmp\/ahriman.lock)]:lock:"
{-l,--lock}"[lock file (default\: ahriman.pid)]:lock:"
"--log-handler[explicit log handler specification. If none set, the handler will be guessed from environment (default\: None)]:log_handler:(console syslog journald)"
{-q,--quiet}"[force disable any logging (default\: False)]"
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
@ -98,6 +99,7 @@ _shtab_ahriman_options=(
_shtab_ahriman_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
@ -119,7 +121,8 @@ _shtab_ahriman_aur_search_options=(
_shtab_ahriman_check_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
@ -153,6 +156,7 @@ _shtab_ahriman_daemon_options=(
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
"--dry-run[just perform check for updates, same as check command (default\: False)]"
{--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:"
@ -207,6 +211,7 @@ _shtab_ahriman_key_import_options=(
_shtab_ahriman_package_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
@ -256,6 +261,7 @@ _shtab_ahriman_package_status_update_options=(
_shtab_ahriman_package_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
@ -278,7 +284,7 @@ _shtab_ahriman_patch_list_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
"*"{-v,--variable}"[if set, show only patches for specified PKGBUILD variables (default\: None)]:variable:"
":package base (default\: None):"
":package base:"
)
_shtab_ahriman_patch_remove_options=(
@ -321,7 +327,8 @@ _shtab_ahriman_repo_backup_options=(
_shtab_ahriman_repo_check_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
@ -363,6 +370,7 @@ _shtab_ahriman_repo_daemon_options=(
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
"--dry-run[just perform check for updates, same as check command (default\: False)]"
{--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:"
@ -437,6 +445,17 @@ _shtab_ahriman_repo_sign_options=(
"(*)::sign only specified packages (default\: None):"
)
_shtab_ahriman_repo_statistics_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--chart[create updates chart and save it to the specified path (default\: None)]:chart:"
{-e,--event}"[event type filter (default\: package-updated)]:event:(package-outdated package-removed package-update-failed package-updated)"
"--from-date[only fetch events which are newer than the date (default\: None)]:from_date:"
"--limit[limit response by specified amount of events (default\: -1)]:limit:"
"--offset[skip specified amount of events (default\: 0)]:offset:"
"--to-date[only fetch events which are older than the date (default\: None)]:to_date:"
":fetch only events for the specified package (default\: None):"
)
_shtab_ahriman_repo_status_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-s,--status}"[new status (default\: success)]:status:(unknown pending building failed success)"
@ -460,6 +479,7 @@ _shtab_ahriman_repo_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
"--dry-run[just perform check for updates, same as check command (default\: False)]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@ -601,6 +621,7 @@ _shtab_ahriman_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
"--dry-run[just perform check for updates, same as check command (default\: False)]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@ -700,6 +721,7 @@ _shtab_ahriman() {
repo-restore) _arguments -C -s $_shtab_ahriman_repo_restore_options ;;
repo-setup) _arguments -C -s $_shtab_ahriman_repo_setup_options ;;
repo-sign) _arguments -C -s $_shtab_ahriman_repo_sign_options ;;
repo-statistics) _arguments -C -s $_shtab_ahriman_repo_statistics_options ;;
repo-status-update) _arguments -C -s $_shtab_ahriman_repo_status_update_options ;;
repo-sync) _arguments -C -s $_shtab_ahriman_repo_sync_options ;;
repo-tree) _arguments -C -s $_shtab_ahriman_repo_tree_options ;;
@ -736,4 +758,12 @@ _shtab_ahriman() {
typeset -A opt_args
_shtab_ahriman "$@"
if [[ $zsh_eval_context[-1] == eval ]]; then
# eval/source/. command, register function for later
compdef _shtab_ahriman -N ahriman
else
# autoload from fpath, call function directly
_shtab_ahriman "$@"
fi

View File

@ -17,11 +17,10 @@ authors = [
]
dependencies = [
"cerberus",
"inflection",
"passlib",
"pyelftools",
"requests",
"srcinfo",
]
dynamic = ["version"]
@ -61,6 +60,9 @@ pacman = [
s3 = [
"boto3",
]
stats = [
"matplotlib",
]
tests = [
"pytest",
"pytest-aiohttp",
@ -70,6 +72,9 @@ tests = [
"pytest-resource-path",
"pytest-spec",
]
validator = [
"cerberus",
]
web = [
"Jinja2",
"aioauth-client",
@ -80,7 +85,8 @@ web = [
"aiohttp_session",
"aiohttp_security",
"cryptography",
"requests-unixsocket", # required by unix socket support
"requests-unixsocket2", # required by unix socket support
"setuptools", # required by aiohttp-apispec
]
[tool.flit.sdist]

View File

@ -12,6 +12,7 @@ Collection of the examples of docker compose configuration files, which covers s
* [Index](index): repository with index page generator enabled.
* [Multi repo](multirepo): run web service with two separated repositories.
* [OAuth](oauth): web service with OAuth (GitHub provider) authentication enabled.
* [PAM](pam): web service with PAM authentication enabled.
* [Pull](pull): normal service, but in addition with pulling packages from another source (e.g. GitHub repository).
* [Sign](sign): create repository with database signing.
* [Web](web): simple web service with authentication enabled.

View File

@ -1,6 +1,7 @@
# Index
1. Setup repository named `ahriman-demo` with architecture `x86_64`.
2. Generate index page.
2. Generate index page and RSS feed.
3. Repository is available at `http://localhost:8080/repo`.
4. Index page is available at `http://localhost:8080/repo/ahriman-demo/x86_64/index.html`
5. Index page is available at `http://localhost:8080/repo/ahriman-demo/x86_64/rss.xml`

View File

@ -1,6 +1,12 @@
[report]
target = html
target = html rss
[html]
path = /var/lib/ahriman/ahriman/repository/ahriman-demo/x86_64/index.html
path = ${repository:root}/repository/ahriman-demo/x86_64/index.html
link_path = http://localhost:8080/repo/ahriman-demo/x86_64
rss_url = ${html:link_path}/rss.xml
[rss]
link_path = ${html:link_path}
path = ${repository:root}/repository/ahriman-demo/x86_64/rss.xml
rss_url = ${html:link_path}/rss.xml

6
recipes/pam/README.md Normal file
View File

@ -0,0 +1,6 @@
# PAM
1. Create system user `demo` with password from `AHRIMAN_PASSWORD` environment variable and group `wheel`.
2. Setup repository named `ahriman-demo` with architecture `x86_64`.
3. Start web server at port `8080`.
4. Repository is available at `http://localhost:8080/repo`.

63
recipes/pam/compose.yml Normal file
View File

@ -0,0 +1,63 @@
services:
backend:
image: arcan1s/ahriman:edge
privileged: true
environment:
AHRIMAN_DEBUG: yes
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: useradd -d / -G wheel -M demo; (cat /run/secrets/password; echo; cat /run/secrets/password) | passwd demo
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock
configs:
- source: service
target: /etc/ahriman.ini.d/99-settings.ini
secrets:
- password
volumes:
- type: volume
source: repository
target: /var/lib/ahriman
volume:
nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web
frontend:
image: nginx
ports:
- 8080:80
configs:
- source: nginx
target: /etc/nginx/conf.d/default.conf
volumes:
- type: volume
source: repository
target: /srv
read_only: true
volume:
nocopy: true
configs:
nginx:
file: nginx.conf
service:
file: service.ini
secrets:
password:
environment: AHRIMAN_PASSWORD
volumes:
repository:

18
recipes/pam/nginx.conf Normal file
View File

@ -0,0 +1,18 @@
server {
listen 80;
location /repo {
rewrite ^/repo/(.*) /$1 break;
autoindex on;
root /srv/ahriman/repository;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarder-Proto $scheme;
proxy_pass http://backend:8080;
}
}

3
recipes/pam/service.ini Normal file
View File

@ -0,0 +1,3 @@
[auth]
target = pam
full_access_group = wheel

View File

@ -17,4 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
__version__ = "2.13.4"
__version__ = "2.15.0"

View File

@ -19,16 +19,16 @@
#
# pylint: disable=too-many-lines
import argparse
import tempfile
from pathlib import Path
from typing import TypeVar
from ahriman import __version__
from ahriman.application import handlers
from ahriman.core.util import enum_values, extract_user
from ahriman.core.utils import enum_values, extract_user
from ahriman.models.action import Action
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.event import EventType
from ahriman.models.log_handler import LogHandler
from ahriman.models.package_source import PackageSource
from ahriman.models.sign_settings import SignSettings
@ -73,8 +73,7 @@ def _parser() -> argparse.ArgumentParser:
parser.add_argument("-c", "--configuration", help="configuration path", type=Path,
default=Path("/") / "etc" / "ahriman.ini")
parser.add_argument("--force", help="force run, remove file lock", action="store_true")
parser.add_argument("-l", "--lock", help="lock file", type=Path,
default=Path(tempfile.gettempdir()) / "ahriman.lock")
parser.add_argument("-l", "--lock", help="lock file", type=Path, default=Path("ahriman.pid"))
parser.add_argument("--log-handler", help="explicit log handler specification. If none set, the handler will be "
"guessed from environment",
type=LogHandler, choices=enum_values(LogHandler))
@ -121,6 +120,7 @@ def _parser() -> argparse.ArgumentParser:
_set_repo_report_parser(subparsers)
_set_repo_restore_parser(subparsers)
_set_repo_sign_parser(subparsers)
_set_repo_statistics_parser(subparsers)
_set_repo_status_update_parser(subparsers)
_set_repo_sync_parser(subparsers)
_set_repo_tree_parser(subparsers)
@ -266,6 +266,8 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"5) and finally you can add package from AUR.",
formatter_class=_formatter)
parser.add_argument("package", help="package source (base name, path to local files, remote URL)", nargs="+")
parser.add_argument("--changes", help="calculate changes from the latest known commit if available",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
@ -446,7 +448,7 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
parser = root.add_parser("patch-list", help="list patch sets",
description="list available patches for the package", formatter_class=_formatter)
parser.add_argument("package", help="package base", nargs="?")
parser.add_argument("package", help="package base")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
action="append")
@ -534,8 +536,10 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
description="check for packages updates. Same as repo-update --dry-run --no-manual",
formatter_class=_formatter)
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("--changes", help="calculate changes from the latest known commit if available. "
"Only applicable in dry run mode",
parser.add_argument("--changes", help="calculate changes from the latest known commit if available",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
@ -605,6 +609,9 @@ def _set_repo_daemon_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("--changes", help="calculate changes from the latest known commit if available. "
"Only applicable in dry run mode",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dry-run", help="just perform check for updates, same as check command", action="store_true")
@ -622,8 +629,7 @@ def _set_repo_daemon_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
"-yy to force refresh even if up to date",
action="count", default=False)
parser.set_defaults(handler=handlers.Daemon, exit_code=False,
lock=Path(tempfile.gettempdir()) / "ahriman-daemon.lock", package=[])
parser.set_defaults(handler=handlers.Daemon, exit_code=False, lock=Path("ahriman-daemon.pid"), package=[])
return parser
@ -732,6 +738,30 @@ def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
return parser
def _set_repo_statistics_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository statistics subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-statistics", help="repository statistics",
description="fetch repository statistics", formatter_class=_formatter)
parser.add_argument("package", help="fetch only events for the specified package", nargs="?")
parser.add_argument("--chart", help="create updates chart and save it to the specified path", type=Path)
parser.add_argument("-e", "--event", help="event type filter",
type=EventType, choices=enum_values(EventType), default=EventType.PackageUpdated)
parser.add_argument("--from-date", help="only fetch events which are newer than the date")
parser.add_argument("--limit", help="limit response by specified amount of events", type=int, default=-1)
parser.add_argument("--offset", help="skip specified amount of events", type=int, default=0)
parser.add_argument("--to-date", help="only fetch events which are older than the date")
parser.set_defaults(handler=handlers.Statistics, lock=None, quiet=True, report=False, unsafe=True)
return parser
def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository status update subcommand
@ -826,6 +856,9 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("--changes", help="calculate changes from the latest known commit if available. "
"Only applicable in dry run mode",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dry-run", help="just perform check for updates, same as check command", action="store_true")
@ -871,7 +904,7 @@ def _set_service_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--pacman", help="clear directory with pacman local database cache",
action=argparse.BooleanOptionalAction, default=False)
parser.set_defaults(handler=handlers.Clean, quiet=True, unsafe=True)
parser.set_defaults(handler=handlers.Clean, lock=None, quiet=True, unsafe=True)
return parser
@ -1130,8 +1163,8 @@ def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("web", help="web server", description="start web server", formatter_class=_formatter)
parser.set_defaults(handler=handlers.Web, architecture="", lock=Path(tempfile.gettempdir()) / "ahriman-web.lock",
report=False, repository="", parser=_parser)
parser.set_defaults(handler=handlers.Web, architecture="", lock=Path("ahriman-web.pid"), report=False,
repository="", parser=_parser)
return parser

View File

@ -62,10 +62,13 @@ class Application(ApplicationPackages, ApplicationRepository):
"""
known_packages: set[str] = set()
# local set
# this action is not really needed in case if ``alpm.use_ahriman_cache`` set to yes, because pacman
# will eventually contain all the local packages
for base in self.repository.packages():
for package, properties in base.packages.items():
known_packages.add(package)
known_packages.update(properties.provides)
# known pacman databases
known_packages.update(self.repository.pacman.packages())
return known_packages
@ -117,8 +120,7 @@ class Application(ApplicationPackages, ApplicationRepository):
process_dependencies(bool): if no set, dependencies will not be processed
Returns:
list[Package]: updated packages list. Packager for dependencies will be copied from
original package
list[Package]: updated packages list. Packager for dependencies will be copied from the original package
Examples:
In the most cases, in order to avoid build failure, it is required to add missing packages, which can be
@ -158,8 +160,7 @@ class Application(ApplicationPackages, ApplicationRepository):
package = Package.from_aur(package_name, username)
with_dependencies[package.base] = package
# register package in local database
self.database.package_base_update(package)
# register package in the database
self.repository.reporter.set_unknown(package)
return list(with_dependencies.values())

View File

@ -27,7 +27,7 @@ from typing import Any
from ahriman.application.application.application_properties import ApplicationProperties
from ahriman.core.build_tools.sources import Sources
from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.util import package_like
from ahriman.core.utils import package_like
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.result import Result
@ -65,7 +65,7 @@ class ApplicationPackages(ApplicationProperties):
"""
package = Package.from_aur(source, username)
self.database.build_queue_insert(package)
self.database.package_base_update(package)
self.reporter.set_unknown(package)
def _add_directory(self, source: str, *_: Any) -> None:
"""
@ -139,7 +139,7 @@ class ApplicationPackages(ApplicationProperties):
"""
package = Package.from_official(source, self.repository.pacman, username)
self.database.build_queue_insert(package)
self.database.package_base_update(package)
self.reporter.set_unknown(package)
def add(self, names: Iterable[str], source: PackageSource, username: str | None = None) -> None:
"""

View File

@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.log import LazyLogging
from ahriman.core.repository import Repository
from ahriman.core.status import Client
from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.repository_id import RepositoryId
@ -39,8 +40,6 @@ class ApplicationProperties(LazyLogging):
def __init__(self, repository_id: RepositoryId, configuration: Configuration, *, report: bool,
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None:
"""
default constructor
Args:
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
@ -63,3 +62,13 @@ class ApplicationProperties(LazyLogging):
str: repository architecture
"""
return self.repository_id.architecture
@property
def reporter(self) -> Client:
"""
instance of the web/database client
Returns:
Client: repository reposter
"""
return self.repository.reporter

View File

@ -39,15 +39,13 @@ class ApplicationRepository(ApplicationProperties):
Args:
packages(Iterable[Package]): list of packages to retrieve changes
"""
last_commit_hashes = self.database.hashes_get()
for package in packages:
last_commit_sha = last_commit_hashes.get(package.base)
last_commit_sha = self.reporter.package_changes_get(package.base).last_commit_sha
if last_commit_sha is None:
continue # skip check in case if we can't calculate diff
changes = self.repository.package_changes(package, last_commit_sha)
self.repository.reporter.package_changes_set(package.base, changes)
self.repository.reporter.package_changes_update(package.base, changes)
def clean(self, *, cache: bool, chroot: bool, manual: bool, packages: bool, pacman: bool) -> None:
"""
@ -91,10 +89,7 @@ class ApplicationRepository(ApplicationProperties):
packages(Iterable[str]): only sign specified packages
"""
# copy to prebuilt directory
for package in self.repository.packages():
# no one requested this package
if packages and package.base not in packages:
continue
for package in self.repository.packages(packages):
for archive in package.packages.values():
if archive.filepath is None:
self.logger.warning("filepath is empty for %s", package.base)
@ -179,7 +174,7 @@ class ApplicationRepository(ApplicationProperties):
return result
def updates(self, filter_packages: Iterable[str], *,
aur: bool, local: bool, manual: bool, vcs: bool) -> list[Package]:
aur: bool, local: bool, manual: bool, vcs: bool, check_files: bool) -> list[Package]:
"""
get list of packages to run update process
@ -189,6 +184,7 @@ class ApplicationRepository(ApplicationProperties):
local(bool): enable or disable checking of local packages for updates
manual(bool): include or exclude manual updates
vcs(bool): enable or disable checking of VCS packages
check_files(bool): check for broken dependencies
Returns:
list[Package]: list of out-of-dated packages
@ -201,5 +197,7 @@ class ApplicationRepository(ApplicationProperties):
updates.update({package.base: package for package in self.repository.updates_local(vcs=vcs)})
if manual:
updates.update({package.base: package for package in self.repository.updates_manual()})
if check_files:
updates.update({package.base: package for package in self.repository.updates_dependencies(filter_packages)})
return [package for _, package in sorted(updates.items())]

View File

@ -49,8 +49,6 @@ class UpdatesIterator(Iterator[list[str] | None]):
def __init__(self, application: Application, interval: int) -> None:
"""
default constructor
Args:
application(Application): application instance
interval(int): predefined interval for updates

View File

@ -37,8 +37,6 @@ class LocalUpdater(Updater):
def __init__(self, repository: Repository) -> None:
"""
default constructor
Args:
repository(Repository): repository instance
"""

View File

@ -43,8 +43,6 @@ class RemoteUpdater(Updater):
def __init__(self, workers: list[Worker], repository_id: RepositoryId, configuration: Configuration) -> None:
"""
default constructor
Args:
workers(list[Worker]): worker identifiers
repository_id(RepositoryId): repository unique identifier

View File

@ -38,6 +38,7 @@ from ahriman.application.handlers.service_updates import ServiceUpdates
from ahriman.application.handlers.setup import Setup
from ahriman.application.handlers.shell import Shell
from ahriman.application.handlers.sign import Sign
from ahriman.application.handlers.statistics import Statistics
from ahriman.application.handlers.status import Status
from ahriman.application.handlers.status_update import StatusUpdate
from ahriman.application.handlers.structure import Structure

View File

@ -50,12 +50,16 @@ class Add(Handler):
application.add(args.package, args.source, args.username)
patches = [PkgbuildPatch.from_env(patch) for patch in args.variable] if args.variable is not None else []
for package in args.package: # for each requested package insert patch
application.database.patches_insert(package, patches)
for patch in patches:
application.reporter.package_patches_update(package, patch)
if not args.now:
return
packages = application.updates(args.package, aur=False, local=False, manual=True, vcs=False)
packages = application.updates(args.package, aur=False, local=False, manual=True, vcs=False, check_files=False)
if args.changes: # generate changes if requested
application.changes(packages)
packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
packagers = Packagers(args.username, {package.base: package.packager for package in packages})

View File

@ -18,10 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import argparse
import pwd
import tarfile
from pathlib import Path
from tarfile import TarFile
from pwd import getpwuid
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
@ -49,7 +49,7 @@ class Backup(Handler):
report(bool): force enable or disable reporting
"""
backup_paths = Backup.get_paths(configuration)
with TarFile(args.path, mode="w") as archive: # well we don't actually use compression
with tarfile.open(args.path, mode="w") as archive: # well we don't actually use compression
for backup_path in backup_paths:
archive.add(backup_path)
@ -77,7 +77,7 @@ class Backup(Handler):
# gnupg home with imported keys
uid, _ = repository_paths.root_owner
system_user = pwd.getpwuid(uid)
system_user = getpwuid(uid)
gnupg_home = Path(system_user.pw_dir) / ".gnupg"
if gnupg_home.is_dir():
paths.add(gnupg_home)

View File

@ -56,4 +56,4 @@ class Change(Handler):
ChangesPrinter(changes)(verbose=True, separator="")
Change.check_if_empty(args.exit_code, changes.is_empty)
case Action.Remove:
client.package_changes_set(args.package, Changes())
client.package_changes_update(args.package, Changes())

View File

@ -59,7 +59,7 @@ class Handler:
repository_id(RepositoryId): repository unique identifier
Returns:
bool: True on success, False otherwise
bool: ``True`` on success, ``False`` otherwise
"""
try:
configuration = Configuration.from_path(args.configuration, repository_id)
@ -129,7 +129,7 @@ class Handler:
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
Args:
enabled(bool): if False no check will be performed
enabled(bool): if ``False`` no check will be performed
predicate(bool): indicates condition on which exception should be thrown
Raises:

View File

@ -98,12 +98,14 @@ class Patch(Handler):
PkgbuildPatch: created patch for the PKGBUILD function
"""
if patch_path is None:
# pylint: disable=bad-builtin
print("Post new function or variable value below. Press Ctrl-D to finish:", file=sys.stderr)
patch = "".join(list(sys.stdin))
else:
patch = patch_path.read_text(encoding="utf8")
patch = patch.strip() # remove spaces around the patch
return PkgbuildPatch(variable, patch)
# remove spaces around the patch and parse to correct type
parsed = PkgbuildPatch.parse(patch.strip())
return PkgbuildPatch(variable, parsed)
@staticmethod
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:
@ -115,25 +117,28 @@ class Patch(Handler):
package_base(str): package base
patch(PkgbuildPatch): patch descriptor
"""
application.database.patches_insert(package_base, [patch])
application.reporter.package_patches_update(package_base, patch)
@staticmethod
def patch_set_list(application: Application, package_base: str | None, variables: list[str] | None,
def patch_set_list(application: Application, package_base: str, variables: list[str] | None,
exit_code: bool) -> None:
"""
list patches available for the package base
Args:
application(Application): application instance
package_base(str | None): package base
package_base(str): package base
variables(list[str] | None): extract patches only for specified PKGBUILD variables
exit_code(bool): exit with error on empty search result
"""
patches = application.database.patches_list(package_base, variables)
patches = [
patch
for patch in application.reporter.package_patches_get(package_base, None)
if variables is None or patch.key in variables
]
Patch.check_if_empty(exit_code, not patches)
for base, patch in patches.items():
PatchPrinter(base, patch)(verbose=True, separator=" = ")
PatchPrinter(package_base, patches)(verbose=True, separator=" = ")
@staticmethod
def patch_set_remove(application: Application, package_base: str, variables: list[str] | None) -> None:
@ -145,4 +150,8 @@ class Patch(Handler):
package_base(str): package base
variables(list[str] | None): remove patches only for specified PKGBUILD variables
"""
application.database.patches_remove(package_base, variables)
if variables is not None:
for variable in variables: # iterate over single variable
application.reporter.package_patches_remove(package_base, variable)
else:
application.reporter.package_patches_remove(package_base, None) # just pass as is

View File

@ -76,7 +76,7 @@ class Rebuild(Handler):
if from_database:
return [
package
for (package, last_status) in application.database.packages_get()
for (package, last_status) in application.reporter.package_get(None)
if status is None or last_status.status == status
]

View File

@ -18,8 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import argparse
from tarfile import TarFile
import tarfile
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
@ -45,5 +44,5 @@ class Restore(Handler):
configuration(Configuration): configuration instance
report(bool): force enable or disable reporting
"""
with TarFile(args.path) as archive:
archive.extractall(path=args.output)
with tarfile.open(args.path) as archive:
archive.extractall(path=args.output) # nosec

View File

@ -43,7 +43,7 @@ class Search(Handler):
SORT_FIELDS = {
field.name
for field in fields(AURPackage)
if field.default_factory is not list # type: ignore[comparison-overlap]
if field.default_factory is not list
}
@classmethod

View File

@ -47,7 +47,7 @@ class ServiceUpdates(Handler):
report(bool): force enable or disable reporting
"""
remote = Package.from_aur("ahriman", None)
_, release = remote.version.rsplit("-", 1) # we don't store pkgrel locally, so we just append it
_, release = remote.version.rsplit("-", maxsplit=1) # we don't store pkgrel locally, so we just append it
local_version = f"{__version__}-{release}"
# technically we would like to compare versions, but it is fine to raise an exception in case if locally

View File

@ -0,0 +1,170 @@
#
# Copyright (c) 2021-2024 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import argparse
import datetime
import itertools
from collections.abc import Callable
from pathlib import Path
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter
from ahriman.core.utils import pretty_datetime
from ahriman.models.event import Event
from ahriman.models.repository_id import RepositoryId
class Statistics(Handler):
"""
repository statistics handler
"""
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
@classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
report: bool) -> None:
"""
callback for command line
Args:
args(argparse.Namespace): command line args
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
report(bool): force enable or disable reporting
"""
application = Application(repository_id, configuration, report=True)
from_date = to_date = None
if (value := args.from_date) is not None:
from_date = datetime.datetime.fromisoformat(value).timestamp()
if (value := args.to_date) is not None:
to_date = datetime.datetime.fromisoformat(value).timestamp()
events = application.reporter.event_get(args.event, args.package, from_date, to_date, args.limit, args.offset)
match args.package:
case None:
Statistics.stats_per_package(args.event, events, args.chart)
case _:
Statistics.stats_for_package(args.event, events, args.chart)
@staticmethod
def event_stats(event_type: str, events: list[Event]) -> None:
"""
calculate event stats
Args:
event_type(str): event type
events(list[Event]): list of events
"""
times = [event.get("took") for event in events if event.get("took") is not None]
EventStatsPrinter(f"{event_type} duration, s", times)(verbose=True)
@staticmethod
def plot_packages(event_type: str, events: dict[str, int], path: Path) -> None:
"""
plot packages frequency
Args:
event_type(str): event type
events(dict[str, int]): list of events
path(Path): path to save plot
"""
from matplotlib import pyplot as plt
x, y = list(events.keys()), list(events.values())
plt.bar(x, y)
plt.xlabel("Package base")
plt.ylabel("Frequency")
plt.title(f"Frequency of the {event_type} event per package")
plt.savefig(path)
@staticmethod
def plot_times(event_type: str, events: list[Event], path: Path) -> None:
"""
plot events timeline
Args:
event_type(str): event type
events(list[Event]): list of events
path(Path): path to save plot
"""
from matplotlib import pyplot as plt
figure = plt.figure()
x, y = zip(*[(pretty_datetime(event.created), event.get("took")) for event in events])
plt.plot(x, y)
plt.xlabel("Event timestamp")
plt.ylabel("Duration, s")
plt.title(f"Duration of the {event_type} event")
figure.autofmt_xdate()
plt.savefig(path)
@staticmethod
def stats_for_package(event_type: str, events: list[Event], chart_path: Path | None) -> None:
"""
calculate statistics for a package
Args:
event_type(str): event type
events(list[Event]): list of events
chart_path(Path): path to save plot if any
"""
# event statistics
Statistics.event_stats(event_type, events)
# chart if enabled
if chart_path is not None:
Statistics.plot_times(event_type, events, chart_path)
@staticmethod
def stats_per_package(event_type: str, events: list[Event], chart_path: Path | None) -> None:
"""
calculate overall statistics
Args:
event_type(str): event type
events(list[Event]): list of events
chart_path(Path): path to save plot if any
"""
key: Callable[[Event], str] = lambda event: event.object_id
by_object_id = {
object_id: len(list(related))
for object_id, related in itertools.groupby(sorted(events, key=key), key=key)
}
# distribution per package
PackageStatsPrinter(by_object_id)(verbose=True)
EventStatsPrinter(f"{event_type} frequency", list(by_object_id.values()))(verbose=True)
# event statistics
Statistics.event_stats(event_type, events)
# chart if enabled
if chart_path is not None:
Statistics.plot_packages(event_type, by_object_id, chart_path)

View File

@ -51,12 +51,8 @@ class StatusUpdate(Handler):
match args.action:
case Action.Update if args.package:
# update packages statuses
packages = application.repository.packages()
for base in args.package:
if (local := next((package for package in packages if package.base == base), None)) is not None:
client.package_add(local, args.status)
else:
client.package_update(base, args.status)
for package in args.package:
client.package_update(package, args.status)
case Action.Update:
# update service status
client.status_update(args.status)

Some files were not shown because too many files have changed in this diff Show More