Commit Graph
14682 Commits
Author SHA1 Message Date
Alejandro Roman 9962429e59 Added playwright testing 2026-06-30 20:37:50 +02:00
kevinveenbirkenbachandClaude Opus 4.8 87c78275b8 feat(meta/complexity): multi-key sort, filter DSL, CI columns
Extend the 'meta roles applications complexity' report:

- --sort takes comma-separated multi-key clauses with per-key direction (e.g. 'desc embeds, asc weight'); replaces --order.
- --variant lists one row per meta/variants.yml variant; --format adds yaml.
- New columns: weight (was total), random, id, row, variants, bundles, jobs, lifecycle, covered_by, compose, swarm.
- covered_by marks the first green (1-based id) different-role predecessor that embeds the row; variant>0 never covered.
- bundles is the compose bundle/job count (whole-role) or 1 (per variant); jobs is the running sum.
- compose/swarm reflect the CI test-deploy skip logic (invokable + tested lifecycle + per-mode skip + swarm deployable variant).
- --filter is a boolean expression DSL (%% == \!= < > <= >=, and/or/xor/not, parens, set literals) over row fields.

Add shared SPOTs: variant_bundles.compose_bundle_counts and variant_status.deployable_variant_indices, reused by the swarm/compose matrix. Update roundtrip.sh/md to --sort "desc weight".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:33:01 +02:00
kevinveenbirkenbach ca039392c3 Merge pull request #365 from infinito-nexus/update/docker-image-versions-web-app-mobilizon-20260630-9b76634
update(images): update Docker image versions (web-app-mobilizon)
2026-06-30 19:59:00 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e391c92f41 fix(web-app-matomo): make swarm bootstrap converge
chown the config dir to www-data before the swarm installer run so the PHP writability checks pass, and raise the healthcheck start_period to 180s to cover the slower swarm/NFS first boot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:22:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8965773827 fix(svc-storage-nfs): pin NFSv4 idmap Domain for ganesha test backend
NFSv4 without a matching idmap Domain squashes non-root owners (www-data uid 33) to nobody (65534) on the client, breaking PHP ownership checks. Pin Domain=localdomain on the ganesha server flavor and the dev/act client, and drop the stale idmap cache. Scoped to dev/act so the production kernel flavor stays untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:21:40 +02:00
Alejandro Roman 2f693f00e6 feat(stalwart):Created the role and the connection like mailu had it 2026-06-30 16:17:48 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3ee35c3c91 fix(ci): treat an absent mode job as N/A, not a failure
failed_roles for the swarm/docker scope only flags a role whose job in that mode actually ran and was not green; total_state is green when every mode that ran is green. A role with no job in a mode (a host driver that never deploys in swarm) is no longer counted as failed for that mode, so 'ci trigger --failed swarm' / 'ci status --failed swarm' stop listing drv-* and other roles that simply do not run in swarm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 13:11:12 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c1fb96584b refactor(tests): rename swarm make targets to swarm-* and reorganize env steps
Rename the scripts/tests/environment deploy_* steps (07/08/09) to compose_*; add 12_swarm.sh (svc-db-mariadb via the swarm-* targets) and 13_roundtrip.sh (svc-db-postgres via make roundtrip), with MARIADB_APP/POSTGRES_APP in common.sh. Rename every make act-swarm-* target to make swarm-* (drop the act- prefix) across the Makefile (moved to the alphabetical slot), the deploy/act, deploy/swarm and e2e helper scripts, and the agent iteration docs. Strip mid-code narration comments from the touched scripts per the comment policy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 80b8d5e9ef fix(ci/compose): copy generated inventory to host before teardown
The 'Zip generated inventory' step reads $INFINITO_INVENTORY_DIR on the
runner host, but the compose deploy writes inventory inside the DiD
container and the cleanup trap removed the container before the always()
zip step ran, so it failed with 'No inventory found under
/home/runner/inventories/github*'. Copy the inventory dir from the
container to the host parent in cleanup() before 'down'/rm; container and
host paths match, so the zip step then finds it. Non-fatal (|| true).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 835fab226e fix(web-app-mastodon): drop dead Further Resources link
The 2daygeek 'check website availability' link returned HTTP 404 and tripped the external-URL reachability test; it was tangential to Mastodon anyway.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4187e1ebab feat(ci): one variant per swarm runner, skip all-disabled variants
In swarm mode (INFINITO_DEPLOY_MODE=swarm) variant_bundles emits one matrix entry per variant (bundle size 1) and drops variants whose meta/variants.yml override disables every service; the all-enabled variant already exercises the role so a bare all-off deploy adds no coverage. Absolute variant indices are preserved so the emitted index still maps to the deploy planner's round. Compose mode is unchanged. Adds the variant_disables_all_services predicate (utils.roles.applications.services.variant_status) plus unit coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 724aeb804a chore(swarm): drop vars orphaned by resolve_host_cid migration
Remove OLLAMA_CONTAINER_ADDRESS, TAIGA_MANAGER_CONTAINER_ADDRESS and
FIDER_CONTAINER_PORT (no remaining references after the cross-node exec
migration and the fider wget removal), and switch the fider swarm tenant
bootstrap from uri to uri_retry for module-lint compliance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 7c99af9355 fix(web-app-fider): probe without wget (absent from image)
The fider image ships only the fider binary (its own healthcheck runs
'./fider ping'), so the swarm in-container wget readiness probe failed
with exec: wget: executable file not found in $PATH. Use './fider ping'
for readiness and post the tenant bootstrap from the hosting node against
the ingress-published routing-mesh port instead of in-container wget.
Compose paths are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 95f414d196 fix(swarm): run in-container exec/inspect on the task's hosting node
container exec/inspect ran on the swarm manager while the task may run on
a worker, yielding No such container or an empty container id. Use the
existing resolve_host_cid helper (HOST_NODE + LOCAL_CID + delegate_to)
for the ollama model pre-pull, the taiga admin migrations and the
peertube post-backfill health inspect, matching the fider/matomo/decidim
pattern. The helper resolves to the local host + compose cid in compose
mode, so that path is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6e4a62f754 fix(web-app-dashboard): make Simple Icons slugs ASCII-safe
slugify only stripped whitespace, so a card title carrying a non-ASCII
character (e.g. U+2011 non-breaking hyphen) produced a non-ASCII slug
that crashed the Simple Icons uri probe with 'ascii' codec can't encode
character. NFKD-normalize then drop non-ASCII; identity for ASCII titles
so existing slugs are unchanged. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 f424ac1007 fix(swarm/proxy): forward internal_port in shared location templates
The healthz, media, upload and ws location templates called proxy_pass
without internal_port, so in swarm they fell back to
services.<entity>.ports.internal.http. Apps whose entity service has no
internal http port (e.g. bluesky) hard-failed the nginx config render
with resolve_upstream: swarm upstream needs
services.<entity>.ports.internal.http. Forward internal_port (default '')
like html.conf.j2 already does; no-op where it is not passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bd62930f1a feat(web-app-bigbluebutton): gate prometheus exporter on the prometheus service
Enable ENABLE_PROMETHEUS_EXPORTER and _OPTIMIZATION via a {% if services.prometheus.enabled %} guard so the bbb-exporter only runs when web-app-prometheus is present, instead of staying hard-commented. Add a head-level '# nocheck: comments-valid' opt-out so the vendored upstream sample.env comments stay valid.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 0d31adc3ab fix(swarm-test): purge inter-round NFS volumes by type instead of a missing nfs key
_context.sh derived NFS_VOLUMES by filtering meta/volumes.yml entries on a per-volume
nfs: key that no role declares, so the inter-round purge cleared no volume data and
round-0 state leaked into round-1. Filter on type==volume instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 0ca2ed56c3 fix(swarm-test): align roundtrip swarm gate to the live workflow step name
The gate grepped a stale step-name marker ("across variant rounds") that never appears
in the act log, so every swarm leg false-failed even on a passing deploy. Match the
actual workflow step name instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c0e4e3934b fix(matomo): extract base domain for root tracking scope via double-quoted scalar
matomo_site_domain used a folded YAML scalar where the regex_replace backslashes are
not unescaped, so base-domain extraction silently returned the input unchanged. In
root tracking scope this registered one Matomo site per consumer subdomain instead of
a single shared registrable-domain site, failing the SitesManager coverage spec.
Use a double-quoted scalar (repo convention) so the regex sees an escaped dot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8390cc4ce4 test(comments): lint .j2 templates and add file-level nocheck opt-out
Drop trap/warning from the exception markers; lint .j2 by stripping the suffix to the underlying language plus Jinja {# #} comments; add a head-level '# nocheck: comments-valid' opt-out via is_suppressed_in_head, documented in suppression.md; strip narration comments from friendica/nextcloud templates and opt the vendored discourse app.yml out with the new marker.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 12:24:18 +02:00
Alejandro Roman 8f64fbb69e Merge remote-tracking branch 'upstream/main' into feature/self-host-runners 2026-06-30 10:20:37 +02:00
Alejandro Roman f4f6ae4366 make local use reinstall properly with all disabled 2026-06-30 10:15:48 +02:00
kevinveenbirkenbach b08c1b9e91 Merge pull request #363 from infinito-nexus/update/repository-refs-web-app-bluesky-20260629-a0337ca
update(repos): bump git refs to latest semver tags (web-app-bluesky)
2026-06-30 09:18:26 +02:00
infinito-nexus-updater[bot] aa66b41a17 update(images): update Docker image versions (web-app-mobilizon) 2026-06-30 06:33:21 +00:00
kevinveenbirkenbach 4411c3fcdc Merge pull request #364 from infinito-nexus/update/docker-image-versions-web-app-funkwhale-20260629-91bdf3f
update(images): update Docker image versions (web-app-funkwhale)
2026-06-30 08:21:16 +02:00
kevinveenbirkenbach 4dda8853c9 Merge branch 'main' into update/docker-image-versions-web-app-funkwhale-20260629-91bdf3f 2026-06-30 08:20:34 +02:00
kevinveenbirkenbach 12cca8b2d0 Merge branch 'main' into feature/web-app-semaphore 2026-06-30 01:43:05 +02:00
kevinveenbirkenbachandClaude Opus 4.8 80e03b4c20 fix(ci): resolve subset roles with venv python
The 🧩 Subset path in pr_affected_roles.sh exec'd a bare `python`, the setup-python interpreter without PyYAML, so subset_roles.py failed with `ModuleNotFoundError: No module named 'yaml'`. Source scripts/meta/env/load.sh so ${PYTHON} resolves to the venv (where PyYAML is installed), matching the diff resolver path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:42:47 +02:00
kevinveenbirkenbach 436fc9ff00 Merge branch 'main' into feature/web-app-semaphore 2026-06-30 01:38:42 +02:00
kevinveenbirkenbachandClaude Opus 4.8 80eb1d1cca fix(web-app-semaphore): make OIDC admin seeding idempotent
On redeploy 'semaphore user add --admin --external' panics with a Postgres unique-constraint violation (duplicate key ... user_username_key), whose message lacks the word 'exist' the failed_when guard looked for, so the task failed. Skip the add when the login already appears in 'semaphore user list', and tolerate 'duplicate key' in failed_when as a safety net.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a96bdbba38 fix(web-app-semaphore): strip base-URL trailing slash for OIDC callback
lookup('tls', ..., 'url.base') always ends with '/', so the OIDC redirect_url and SEMAPHORE_WEB_ROOT contained a double slash (...example//api/...). The '//api/...' callback path did not match the oauthstate cookie's default path '/api/auth/oidc/keycloak', so Semaphore reported 'http: named cookie not present' and bounced OIDC logins back to /auth/login. Apply regex_replace('/+$', '') (same idiom as web-app-keycloak) to both values; Keycloak's redirect URIs use a '/*' wildcard so the single-slash callback still matches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c28ea68326 fix(web-app-semaphore): pin published image tag v2.18.12
v2.18.13 is not published on Docker Hub, so 'compose pull' failed with 'manifest unknown' and aborted the deploy. Pin v2.18.12 (latest stable 2.x, verified pullable in the nested daemon) and align the README bump-policy note and the 028 requirement spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:41 +02:00
kevinveenbirkenbach 06f6c45455 Release 11.3.0 2026-06-30 01:38:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 42892bc1b4 chore(claude): gitignore local agent artifacts (launch.json, routines, workflows)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 53405a4fb1 fix(ci): fix odoo sale_management spec and harden flaky deploys
odoo: sale_management.spec.js asserted `breadcrumb.or(appTitle)` without
`.first()`; when the Sales module installs correctly BOTH the menu brand
and the breadcrumb render, so `.or()` resolved to 2 elements and
`toBeVisible()` raised a strict-mode violation — failing the success case.
Add `.first()` (matching the same file's createQuotation locator).

nextcloud: the GitLab OAuth provisioning hard-`raise`d when no Organization
existed yet (default org is seeded asynchronously). Resolve/create it
defensively and add `retries/until` so a transient not-yet-seeded window no
longer fails the whole deploy.

jenkins: the deploy-lockdown service stop had no retry; under load systemd
intermittently refused with "Transaction is destructive". Add `retries/until`
so the transient contention is ridden out.

moodle: the shared `compose up` handler had no retry; a transient missing
external network (central DB stack still creating it) failed the deploy. Add
`retries/until`, matching the handler's existing compose-pull pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 926271478b fix(security): resolve all open code-scanning alerts and guard against recurrence
Resolve the 80 open CodeQL/code-scanning alerts on this branch.

Security-sensitive fixes:
- cli/administration/deploy/development: break the unsafe import cycle by
  extracting the env/arg helpers into a leaf module `env.py`, giving the
  load-time DAG compose -> common -> deps -> env.
- web-app-bluesky login-broker server.js: prototype-pollution guard on
  cookie parsing, CR/LF + control-char log sanitisation, HTML-escaped
  exception text, and a ReDoS-bounded handle regex.
- web-app-baserow SSO: harden the open-redirect `next` handling.
- network diagnose probes: require TLS >= 1.2.
- actionlint installer: validate tar members against path traversal.
- decidim/apt-purge lint regexes: rewrite to avoid catastrophic backtracking.
- 6x Playwright URL regexes anchored; crs-k/stale-branches pinned to a commit SHA.

Mechanical cleanups: unused imports/globals/locals, empty-except comments,
import-and-import-from, implicit-string-concat, multiple-definition,
unreachable/useless-assignment.

False positives are intentionally left in place (Django settings patches,
Odoo __manifest__, side-effect imports, cross-module symbols).

Recurrence guards:
- import-linter contract (pyproject + tests/lint) locks the dev-deploy
  package acyclic; a new cycle now fails CI instead of only CodeQL.
- new lint test requires every bandit (S###) `noqa` to carry a justification.
- BLE001 (blind-except) added to ruff as a ratchet (tests/roles exempt,
  current production offenders grandfathered).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:40 +02:00
infinito-nexus-updater[bot] 10bdd79fce update(images): update Docker image versions (web-app-seaweedfs) 2026-06-30 01:38:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a129cb6e71 revert(ci): restore secrets: inherit for the fork image mirror
Untrusted fork PRs mirrored anonymously after the credential hardening (empty Docker Hub creds -> Login to Docker Hub skipped -> anonymous pulls), which got rate-limited and failed images-mirror-missing-fork. Restore secrets: inherit on the fork mirror job and the GHCR login token so the mirror authenticates again. The build keeps its hardening (it pulls its parent from GHCR and needs no Docker Hub creds).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 01:38:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 afc9a3f759 fix(ci): satisfy stale-branches v9 day-window validation
crs-k/stale-branches@v9.0.1 rejects days-before-stale >= days-before-delete (the v8 'delete immediately' behaviour with days-before-delete: 0 is gone), so the daily cleanup failed with 'Invalid inputs'. Set days-before-stale: 350 and days-before-delete: 360 - deletion still triggers at 360 days of inactivity, with a 10-day stale warning before it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 01:38:40 +02:00
kevinveenbirkenbach 0828f8cf7c Release 11.3.0 2026-06-30 01:38:39 +02:00
dependabot[bot] 8751706204 chore(deps): bump actions/stale from 9 to 10
Bumps [actions/stale](https://github.com/actions/stale) from 9 to 10.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v9...v10)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-30 01:38:39 +02:00
dependabot[bot] 2f344b8bba chore(deps-dev): bump eslint from 10.5.0 to 10.6.0
Bumps [eslint](https://github.com/eslint/eslint) from 10.5.0 to 10.6.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.5.0...v10.6.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-30 01:38:39 +02:00
infinito-nexus-updater[bot] 2476c74844 update(repos): bump git refs to latest semver tags (pkgmgr) 2026-06-30 01:38:39 +02:00
kevinveenbirkenbach 179d295144 Merge pull request #353 from kevinveenbirkenbach/fix/security
fix(security): resolve all open code-scanning alerts and guard against recurrence
2026-06-30 01:38:38 +02:00
kevinveenbirkenbach 82270d685e Merge pull request #361 from infinito-nexus/update/docker-image-versions-web-app-seaweedfs-20260629-2993b62
update(images): update Docker image versions (web-app-seaweedfs)
2026-06-30 01:38:38 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4a9c7fb254 chore(claude): gitignore local agent artifacts (launch.json, routines, workflows)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:38 +02:00
kevinveenbirkenbachandClaude Opus 4.8 2f80af0228 fix(ci): fix odoo sale_management spec and harden flaky deploys
odoo: sale_management.spec.js asserted `breadcrumb.or(appTitle)` without
`.first()`; when the Sales module installs correctly BOTH the menu brand
and the breadcrumb render, so `.or()` resolved to 2 elements and
`toBeVisible()` raised a strict-mode violation — failing the success case.
Add `.first()` (matching the same file's createQuotation locator).

nextcloud: the GitLab OAuth provisioning hard-`raise`d when no Organization
existed yet (default org is seeded asynchronously). Resolve/create it
defensively and add `retries/until` so a transient not-yet-seeded window no
longer fails the whole deploy.

jenkins: the deploy-lockdown service stop had no retry; under load systemd
intermittently refused with "Transaction is destructive". Add `retries/until`
so the transient contention is ridden out.

moodle: the shared `compose up` handler had no retry; a transient missing
external network (central DB stack still creating it) failed the deploy. Add
`retries/until`, matching the handler's existing compose-pull pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:38:38 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1d33586eb2 revert(ci): restore secrets: inherit for the fork image mirror
Untrusted fork PRs mirrored anonymously after the credential hardening (empty Docker Hub creds -> Login to Docker Hub skipped -> anonymous pulls), which got rate-limited and failed images-mirror-missing-fork. Restore secrets: inherit on the fork mirror job and the GHCR login token so the mirror authenticates again. The build keeps its hardening (it pulls its parent from GHCR and needs no Docker Hub creds).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 01:38:37 +02:00
infinito-nexus-updater[bot] 3da854f959 update(images): update Docker image versions (web-app-seaweedfs) 2026-06-30 01:38:37 +02:00