From d987a46664060cec4eb7a4e900add28cef8d4a4b Mon Sep 17 00:00:00 2001 From: eabdullin Date: Tue, 4 Feb 2025 09:15:19 +0000 Subject: [PATCH] Import from CS git --- .galera.metadata | 2 +- .gitignore | 2 +- ...4d612359a294312943271abaf40685115fda.patch | 374 ------------------ SOURCES/docs.patch | 25 ++ SOURCES/garbd-wrapper | 38 -- SOURCES/garbd.service | 10 - SPECS/galera.spec | 38 +- 7 files changed, 50 insertions(+), 439 deletions(-) delete mode 100644 SOURCES/4e214d612359a294312943271abaf40685115fda.patch create mode 100644 SOURCES/docs.patch delete mode 100755 SOURCES/garbd-wrapper delete mode 100644 SOURCES/garbd.service diff --git a/.galera.metadata b/.galera.metadata index a0ec6ba..4e37e95 100644 --- a/.galera.metadata +++ b/.galera.metadata @@ -1 +1 @@ -2c3019ae05300adcdd6afae72e9c16ef14a37e5c SOURCES/galera-26.4.16.tar.gz +ed55d57a704512140b3979d94b6ff0691c0a6227 SOURCES/galera-26.4.20.tar.gz diff --git a/.gitignore b/.gitignore index 0d9207b..f3036d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/galera-26.4.16.tar.gz +SOURCES/galera-26.4.20.tar.gz diff --git a/SOURCES/4e214d612359a294312943271abaf40685115fda.patch b/SOURCES/4e214d612359a294312943271abaf40685115fda.patch deleted file mode 100644 index b83930d..0000000 --- a/SOURCES/4e214d612359a294312943271abaf40685115fda.patch +++ /dev/null @@ -1,374 +0,0 @@ -Taken from: - https://github.com/codership/galera/commit/4e214d612359a294312943271abaf40685115fda.patch - -Reson: - The SSL certifactes expired, which resulted in the test failing: - | 85%: Checks: 77, Failures: 0, Errors: 11 - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1019:E:test_ssl_connect:test_ssl_connect:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1031:E:test_ssl_connect_twice:test_ssl_connect_twice:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1046:E:test_ssl_async_read_write:test_ssl_async_read_write:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1058:E:test_ssl_async_read_write_large:test_ssl_async_read_write_large:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:636:E:test_ssl_async_read_write_small_large:test_ssl_async_read_write_small_large:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1083:E:test_ssl_async_read_from_client_write_from_server:test_ssl_async_read_from_client_write_from_server:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1096:E:test_ssl_write_twice_wo_handling:test_ssl_write_twice_wo_handling:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1109:E:test_ssl_close_client:test_ssl_close_client:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1121:E:test_ssl_close_server:test_ssl_close_server:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1133:E:test_ssl_get_tcp_info:test_ssl_get_tcp_info:0: (after this point) Test timeout expired - | /builddir/build/BUILD/galera-26.4.16/galerautils/tests/gu_asio_test.cpp:1145:E:test_ssl_compression_option:test_ssl_compression_option:0: (after this point) Test timeout expired - ---- - -From 4e214d612359a294312943271abaf40685115fda Mon Sep 17 00:00:00 2001 -From: Teemu Ollakka -Date: Mon, 2 Oct 2023 20:31:37 +0300 -Subject: [PATCH] codership/galera#647 Generate keys and certificates for SSL - tests - -Relying on static certificates causes several problems: -- Certificates eventually expire, which causes surprises - when tests suddenly stop passing without prior warning. -- Standards change, a certificate created on different - platform long time ago may not be usable on some more - modern platform. -- Lack of fine grained control on test scenarios without - generating and storing several certificates in source - repository. - -In order to work around the problems above, generate -certificates programmatically before the tests are run. -The generated certificates use the same versioning and -extensions as the original ones under tests/conf. ---- - galerautils/tests/CMakeLists.txt | 4 +- - galerautils/tests/gu_asio_test.cpp | 269 ++++++++++++++++++++++++++++- - 3 files changed, 266 insertions(+), 8 deletions(-) - -diff --git a/galerautils/tests/CMakeLists.txt b/galerautils/tests/CMakeLists.txt -index f863ce66b..a44b2d6b3 100644 ---- a/galerautils/tests/CMakeLists.txt -+++ b/galerautils/tests/CMakeLists.txt -@@ -47,7 +47,6 @@ add_test( - # - # C++ galerautils tests. - # -- - add_executable(gu_tests++ - gu_atomic_test.cpp - gu_gtid_test.cpp -@@ -75,7 +74,7 @@ add_executable(gu_tests++ - - target_compile_definitions(gu_tests++ - PRIVATE -- -DGU_ASIO_TEST_CERT_DIR="${PROJECT_SOURCE_DIR}/tests/conf") -+ -DGU_ASIO_TEST_CERT_DIR="${CMAKE_CURRENT_BINARY_DIR}/certs") - - # TODO: These should be eventually fixed. - target_compile_options(gu_tests++ -@@ -93,7 +92,6 @@ add_test( - NAME gu_tests++ - COMMAND gu_tests++ - ) -- - # - # Deqmap micro benchmark. - # -diff --git a/galerautils/tests/gu_asio_test.cpp b/galerautils/tests/gu_asio_test.cpp -index c4c948bda..616902eb1 100644 ---- a/galerautils/tests/gu_asio_test.cpp -+++ b/galerautils/tests/gu_asio_test.cpp -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2019-2020 Codership Oy -+ * Copyright (C) 2019-2023 Codership Oy - */ - - -@@ -920,18 +920,276 @@ END_TEST - - #ifdef GALERA_HAVE_SSL - -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include - #include - --// --// SSL --// -+#include - - static std::string get_cert_dir() - { -- // This will be set by CMake/preprocessor. -+ static_assert(::strlen(GU_ASIO_TEST_CERT_DIR) > 0); -+ const std::string ret{ GU_ASIO_TEST_CERT_DIR }; -+ auto* dir = opendir(ret.c_str()); -+ if (!dir) -+ { -+ if (mkdir(ret.c_str(), S_IRWXU)) -+ { -+ const auto* errstr = ::strerror(errno); -+ gu_throw_fatal << "Could not create dir " << ret << ": " << errstr; -+ } -+ } -+ else -+ { -+ closedir(dir); -+ } - return GU_ASIO_TEST_CERT_DIR; - } - -+static int password_cb(char*, int, int, void*) { return 0; } -+ -+static void throw_error(const char* msg) -+{ -+ gu_throw_fatal << msg << ": " << ERR_error_string(ERR_get_error(), nullptr); -+} -+ -+static EVP_PKEY* create_key() -+{ -+#if OPENSSL_VERSION_MAJOR < 3 -+ auto* bn = BN_new(); -+ if (!bn) -+ { -+ throw_error("could not create BN"); -+ } -+ BN_set_word(bn, 0x10001); -+ auto* rsa = RSA_new(); -+ if (!rsa) -+ { -+ BN_free(bn); -+ throw_error("could not create RSA"); -+ } -+ RSA_generate_key_ex(rsa, 2048, bn, nullptr); -+ auto* pkey = EVP_PKEY_new(); -+ if (!pkey) -+ { -+ BN_free(bn); -+ RSA_free(rsa); -+ throw_error("could not create PKEY"); -+ } -+ EVP_PKEY_set1_RSA(pkey, rsa); -+ RSA_free(rsa); -+ BN_free(bn); -+ return pkey; -+#else -+ auto* ret = EVP_RSA_gen(2048); -+ if (!ret) -+ { -+ throw_error("could not create RSA"); -+ } -+ return ret; -+#endif /* OPENSSL_VERSION_MAJOR < 3 */ -+} -+ -+static FILE* open_file(const std::string& path, const char* mode) -+{ -+ auto* ret = fopen(path.c_str(), mode); -+ if (!ret) -+ { -+ const auto* errstr = ::strerror(errno); -+ gu_throw_fatal << "Could not open file " << path << ": " -+ << errstr; -+ } -+ return ret; -+} -+ -+static void write_key(EVP_PKEY* pkey, const std::string& filename) -+{ -+ const std::string cert_dir = get_cert_dir(); -+ const std::string key_file_path = cert_dir + "/" + filename; -+ auto* key_file = open_file(key_file_path, "wb"); -+ if (!PEM_write_PrivateKey(key_file, pkey, nullptr, nullptr, 0, password_cb, -+ nullptr)) -+ { -+ throw_error("Could not write key"); -+ } -+ fclose(key_file); -+} -+ -+static void set_x509v3_extensions(X509* x509, X509* issuer) -+{ -+ auto* conf_bio = BIO_new(BIO_s_mem()); -+ std::string ext{ "[extensions]\n" -+ "authorityKeyIdentifier=keyid,issuer\n" -+ "subjectKeyIdentifier=hash\n" }; -+ if (!issuer) -+ { -+ ext += "basicConstraints=critical,CA:TRUE\n"; -+ } -+ else -+ { -+ ext += "keyUsage=digitalSignature,keyEncipherment\n"; -+ ext += "basicConstraints=CA:FALSE\n"; -+ } -+ BIO_printf(conf_bio, "%s", ext.c_str()); -+ auto* conf = NCONF_new(nullptr); -+ long errorline = -1; -+ int err; -+ if ((err = NCONF_load_bio(conf, conf_bio, &errorline)) <= 0) -+ { -+ gu_throw_fatal << "Could not load conf: " << err; -+ } -+ if (errorline != -1) -+ { -+ gu_throw_fatal << "Could not load conf, errorline: " << errorline; -+ } -+ // TODO: V3 extensions -+ X509V3_CTX ctx; -+ X509V3_set_ctx(&ctx, issuer ? issuer : x509, x509, nullptr, nullptr, 0); -+ X509V3_set_nconf(&ctx, conf); -+ if (!X509V3_EXT_add_nconf(conf, &ctx, "extensions", x509)) -+ { -+ throw_error("Could not add extension"); -+ } -+ NCONF_free(conf); -+ BIO_free(conf_bio); -+} -+ -+static X509* create_x509(EVP_PKEY* pkey, X509* issuer, const char* cn) -+{ -+ auto* x509 = X509_new(); -+ /* According to standard, value 2 means version 3. */ -+ X509_set_version(x509, 2); -+ ASN1_INTEGER_set(X509_get_serialNumber(x509), 1); -+ X509_gmtime_adj(X509_get_notBefore(x509), 0); -+ X509_gmtime_adj(X509_get_notAfter(x509), 31536000L); -+ X509_set_pubkey(x509, pkey); -+ -+ auto* name = X509_get_subject_name(x509); -+ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*)"FI", -+ -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, -+ (unsigned char*)"Uusimaa", -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, -+ (unsigned char*)"Helsinki", -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, -+ (unsigned char*)"Codership", -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, -+ (unsigned char*)"Galera Devel", -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)cn, -1, -+ -1, 0); -+ if (!issuer) -+ { -+ /* Self signed */ -+ X509_set_issuer_name(x509, name); -+ } -+ else -+ { -+ X509_set_issuer_name(x509, X509_get_subject_name(issuer)); -+ } -+ -+ set_x509v3_extensions(x509, issuer); -+ -+ X509_sign(x509, pkey, EVP_sha256()); -+ -+ return x509; -+} -+ -+static void write_x509(X509* x509, const std::string& filename) -+{ -+ const std::string cert_dir = get_cert_dir(); -+ const std::string file_path = cert_dir + "/" + filename; -+ auto* file = open_file(file_path, "wb"); -+ if (!PEM_write_X509(file, x509)) -+ { -+ throw_error("Could not write x509"); -+ } -+ fclose(file); -+} -+ -+static void write_x509_list(const std::vector& certs, -+ const std::string& filename) -+{ -+ const std::string cert_dir = get_cert_dir(); -+ const std::string file_path = cert_dir + "/" + filename; -+ auto* file = open_file(file_path, "wb"); -+ for (auto* x509 : certs) -+ { -+ if (!PEM_write_X509(file, x509)) -+ { -+ throw_error("Could not write x509"); -+ } -+ } -+ fclose(file); -+} -+ -+/* Self signed CA + certificate */ -+static void generate_self_signed() -+{ -+ auto* pkey = create_key(); -+ write_key(pkey, "galera_key.pem"); -+ auto* ca = create_x509(pkey, nullptr, "Galera Root"); -+ write_x509(ca, "galera_ca.pem"); -+ -+ auto* cert = create_x509(pkey, ca, "Galera Cert"); -+ write_x509(cert, "galera_cert.pem"); -+ X509_free(cert); -+ X509_free(ca); -+ EVP_PKEY_free(pkey); -+} -+ -+/* -+ ---- Server cert 1 -+ / -+ Root CA - Intermediate CA -+ \---- Server cert 2 -+ -+ Two bundles consisting of intermediate CA and server certificate -+ are created for servers 1 and 2. -+ */ -+static void generate_chains() -+{ -+ auto* root_ca_key = create_key(); -+ auto* root_ca = create_x509(root_ca_key, nullptr, "Galera Root CA"); -+ auto* int_ca_key = create_key(); -+ auto* int_ca = create_x509(int_ca_key, root_ca, "Galera Intermediate CA"); -+ -+ auto* server_1_key = create_key(); -+ auto* server_1_cert = create_x509(server_1_key, int_ca, "Galera Server 1"); -+ auto* server_2_key = create_key(); -+ auto* server_2_cert = create_x509(server_2_key, int_ca, "Galera Server 2"); -+ -+ write_x509(root_ca, "galera-ca.pem"); -+ write_key(server_1_key, "galera-server-1.key"); -+ write_x509_list({ server_1_cert, int_ca }, "bundle-galera-server-1.pem"); -+ write_key(server_2_key, "galera-server-2.key"); -+ write_x509_list({ server_2_cert, int_ca }, "bundle-galera-server-2.pem"); -+ -+ X509_free(server_2_cert); -+ EVP_PKEY_free(server_2_key); -+ X509_free(server_1_cert); -+ EVP_PKEY_free(server_1_key); -+ X509_free(int_ca); -+ EVP_PKEY_free(int_ca_key); -+ X509_free(root_ca); -+ EVP_PKEY_free(root_ca_key); -+} -+ -+static void generate_certificates() -+{ -+ generate_self_signed(); -+ generate_chains(); -+} -+ -+// -+// SSL -+// -+ - static gu::Config get_ssl_config() - { - gu::Config ret; -@@ -2173,6 +2431,7 @@ Suite* gu_asio_suite() - // - // SSL - // -+ generate_certificates(); - - tc = tcase_create("test_ssl_io_service"); - tcase_add_test(tc, test_ssl_io_service); diff --git a/SOURCES/docs.patch b/SOURCES/docs.patch new file mode 100644 index 0000000..7a6bec5 --- /dev/null +++ b/SOURCES/docs.patch @@ -0,0 +1,25 @@ +The CMake prepares file AUTHORS for packing. +It only contains one line, and isn't packed in any upstream-produced packagess. +I don't find it useful and since upstream doesn't pack it either, stop packing it here. + +The README file contains infromation on how to build the project from sources, and thus isn't useful for the end users. + +On the other hand, the README-MySQL isn't prepared for packing by CMake, but contains useful information about the software usage and it is package in upstream-produced packages. + +Offered upstream: +https://github.com/codership/galera/pull/666 +https://groups.google.com/g/codership-team/c/Cn4UO3MkNQs + +--- galera-26.4.18/CMakeLists.txt 2024-06-09 04:54:56.281408893 +0200 ++++ galera-26.4.18/CMakeLists.txt_patched 2024-06-09 06:52:58.093217968 +0200 +@@ -118,9 +118,8 @@ endif() + + if (NOT ${CMAKE_SYSTEM_NAME} MATCHES ".*BSD") + install(FILES +- ${PROJECT_SOURCE_DIR}/AUTHORS + ${PROJECT_SOURCE_DIR}/COPYING +- ${PROJECT_SOURCE_DIR}/README ++ ${PROJECT_SOURCE_DIR}/scripts/packages/README-MySQL + DESTINATION ${INSTALL_DOCDIR} ) + install(FILES ${PROJECT_SOURCE_DIR}/asio/LICENSE_1_0.txt + DESTINATION ${INSTALL_DOCDIR} diff --git a/SOURCES/garbd-wrapper b/SOURCES/garbd-wrapper deleted file mode 100755 index ede76f7..0000000 --- a/SOURCES/garbd-wrapper +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/sh -# This script is simple wrapper around garbd, that parses startup configuration. -# Its main purpose is to bridge the differences between initscript and systemd unit file. - -CONFIG_FILE=/etc/sysconfig/garb - -source $CONFIG_FILE - -# Check that node addresses and group name are configured -if [ -z "$GALERA_NODES" ]; then - echo "List of GALERA_NODES is not configured" >&2 - exit 1 -fi -if [ -z "$GALERA_GROUP" ]; then - echo "GALERA_GROUP name is not configured" >&2 - exit 1 -fi - -GALERA_PORT=${GALERA_PORT:-4567} - -# Find a working node -for ADDRESS in ${GALERA_NODES} 0; do - HOST=$(echo $ADDRESS | cut -d \: -f 1) - PORT=$(echo $ADDRESS | cut -s -d \: -f 2) - PORT=${PORT:-$GALERA_PORT} - ncat --send-only --recv-only $HOST $PORT >/dev/null && break -done -if [ ${ADDRESS} == "0" ]; then - echo "None of the nodes in GALERA_NODES is accessible" >&2 - exit 1 -fi - -OPTIONS="-a gcomm://$ADDRESS" -[ -n "$GALERA_GROUP" ] && OPTIONS="$OPTIONS -g $GALERA_GROUP" -[ -n "$GALERA_OPTIONS" ] && OPTIONS="$OPTIONS -o $GALERA_OPTIONS" -[ -n "$LOG_FILE" ] && OPTIONS="$OPTIONS -l $LOG_FILE" - -exec /usr/sbin/garbd $OPTIONS diff --git a/SOURCES/garbd.service b/SOURCES/garbd.service deleted file mode 100644 index 9645fe2..0000000 --- a/SOURCES/garbd.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Galera Arbitrator Daemon -Documentation=http://www.codership.com/wiki/doku.php?id=galera_arbitrator - -[Service] -ExecStart=/usr/sbin/garbd-wrapper -ExecReload=/bin/kill -HUP $MAINPID - -[Install] -WantedBy=multi-user.target diff --git a/SPECS/galera.spec b/SPECS/galera.spec index dba5a27..8df79e4 100644 --- a/SPECS/galera.spec +++ b/SPECS/galera.spec @@ -1,5 +1,8 @@ +# To both save infrastrucutre resources and workaround for i686 FTBFS +ExcludeArch: %{ix86} + Name: galera -Version: 26.4.16 +Version: 26.4.20 Release: 1%{?dist} Summary: Synchronous multi-master wsrep provider (replication engine) @@ -12,11 +15,8 @@ URL: http://galeracluster.com/ Source0: http://releases.galeracluster.com/source/%{name}-%{version}.tar.gz -Source1: garbd.service -Source2: garbd-wrapper - Patch0: cmake_paths.patch -Patch1: 4e214d612359a294312943271abaf40685115fda.patch +Patch1: docs.patch BuildRequires: boost-devel check-devel openssl-devel cmake systemd gcc-c++ asio-devel Requires(pre): /usr/sbin/useradd @@ -35,8 +35,8 @@ description of Galera replication engine see https://www.galeracluster.com web. %prep %setup -q -%patch0 -p1 -%patch1 -p1 +%patch -P0 -p1 +%patch -P1 -p1 %build %{set_build_flags} @@ -72,13 +72,13 @@ cmake -B %_vpath_builddir -LAH # Fedora downstream packaging historically used "garbd" name for the service. # # Let's stick with the Fedora legacy naming, AND provide an alias to the Galera upstream name -mv %{buildroot}/usr/lib/systemd/system/garb.service %{buildroot}/usr/lib/systemd/system/garbd.service -sed -i 's/Alias=garbd.service/Alias=garb.service/g' %{buildroot}/usr/lib/systemd/system/garbd.service +mv %{buildroot}%{_unitdir}/garb.service %{buildroot}%{_unitdir}/garbd.service +sed -i 's/Alias=garbd.service/Alias=garb.service/g' %{buildroot}%{_unitdir}/garbd.service # PATCH 2: # Fix the hardcoded paths # In the Systemd service file: -sed -i 's;/usr/bin/garb-systemd;/usr/sbin/garb-systemd;g' %{buildroot}/usr/lib/systemd/system/garbd.service +sed -i 's;/usr/bin/garb-systemd;/usr/sbin/garb-systemd;g' %{buildroot}%{_unitdir}/garbd.service # In the wrapper script: sed -i 's;/usr/bin/garbd;/usr/sbin/garbd;g' %{buildroot}/usr/sbin/garb-systemd @@ -105,7 +105,9 @@ sed -i 's;/usr/bin/garbd;/usr/sbin/garbd;g' %{buildroot}/usr/sbin/garb-systemd ## in particular on systems using NFS or running containers. Allocate a user ID ## specific to this service, either statically via systemd-sysusers or dynamically ## via the DynamicUser= service setting. -sed -i 's/User=nobody/User=garb/g' %{buildroot}/usr/lib/systemd/system/garbd.service +sed -i 's/User=nobody/User=garb/g' %{buildroot}%{_unitdir}/garbd.service +# Maintainers from other distributions also tries to resolve it on the upstream: +# https://github.com/codership/galera/pull/633 %check @@ -134,7 +136,6 @@ sed -i 's/User=nobody/User=garb/g' %{buildroot}/usr/lib/systemd/system/garbd.ser %dir %{_libdir}/galera %{_sbindir}/garbd -#%{_sbindir}/garbd-wrapper # PATCH 3: # Make sure the wrapper script is executable @@ -146,14 +147,21 @@ sed -i 's/User=nobody/User=garb/g' %{buildroot}/usr/lib/systemd/system/garbd.ser %{_libdir}/galera/libgalera_smm.so -%doc %{_docdir}/galera/AUTHORS %doc %{_docdir}/galera/COPYING %doc %{_docdir}/galera/LICENSE.asio -%doc %{_docdir}/galera/README -#%doc %{_docdir}/galera/README-MySQL +%doc %{_docdir}/galera/README-MySQL %changelog +* Thu Nov 14 2024 Michal Schorm - 26.4.20-1 +- Rebase to 26.4.20 + +* Fri Oct 18 2024 Michal Schorm - 26.4.19-1 +- Rebase to 26.4.19 + +* Fri Jun 07 2024 Michal Schorm - 26.4.18-1 +- Rebase to 26.4.18 + * Fri Nov 17 2023 Michal Schorm - 26.4.16-1 - Rebase to 26.4.16