commit: 3f8aea009a4fa202b76e48495758a81ecd561bba
Author: Nicolas PARLANT <nicolas.parlant <AT> parhuet <DOT> fr>
AuthorDate: Fri Jun 6 10:19:19 2025 +0000
Commit: Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Thu Jun 12 08:06:38 2025 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=3f8aea00
net-misc/kea: add 2.6.3
update SRC_URI
license is now MPL-2.0
remove brand sed-op from previous ebuild
fix, sed-op :
fix paths for gtest detection
skip failing tests (maybe more depending of tinderbox)
update service/initrd/confd :
unprivileged user 'dhcp'
use capabilities instead of fcap
install unconditionnaly default config from upstream examples in /etc/kea/
eclass, move to python-r1 :
ensure a shared built-time target for sphinx/sphinx-rtd-theme
kea-shell is now installed with portage's functions instead of autotools.
deps :
add boost support for dev-libs/botan2, required
if mysql, add inherited libs from mysql-connector-c :
dev-libs/openssl, sys-libs/zlib and app-arch/zstd
options :
enable logger-checks by default
Bug: https://bugs.gentoo.org/946391
Bug: https://bugs.gentoo.org/957113
Closes: https://bugs.gentoo.org/928320
Signed-off-by: Nicolas PARLANT <nicolas.parlant <AT> parhuet.fr>
Part-of: https://github.com/gentoo/gentoo/pull/42481
Signed-off-by: Sam James <sam <AT> gentoo.org>
net-misc/kea/Manifest | 1 +
net-misc/kea/files/kea-confd-r2 | 12 ++
net-misc/kea/files/kea-ctrl-agent.service-r2 | 16 ++
net-misc/kea/files/kea-dhcp-ddns.service-r2 | 17 ++
net-misc/kea/files/kea-dhcp4.service-r2 | 17 ++
net-misc/kea/files/kea-dhcp6.service-r2 | 17 ++
net-misc/kea/files/kea-initd-r2 | 147 ++++++++++++++++
net-misc/kea/kea-2.6.3.ebuild | 253 +++++++++++++++++++++++++++
8 files changed, 480 insertions(+)
diff --git a/net-misc/kea/Manifest b/net-misc/kea/Manifest
index 41c4c96ee2a4..a52653a425a3 100644
--- a/net-misc/kea/Manifest
+++ b/net-misc/kea/Manifest
@@ -1 +1,2 @@
DIST kea-2.4.1.tar.gz 10487415 BLAKE2B
21037d28f812ebbc65ae34f5151a209e9c74f6aa005e96ed7cbbf6e4250e6c40eecf5d257b852bf01663a0982b5401008dd6a51a16d861b30a83549f827538b6
SHA512
b8a3b6f2cae213fd9826c37568c71d3458f52eed973dbe437a1d0974dafa026635a730d828c6ff03b32e030be57d75a7914a8ca313833e91d9996b6a05b2b224
+DIST kea-2.6.3.tar.gz 10498882 BLAKE2B
7a8549ceb86dccaa2ca8d541cbfd27618ccf8aeedfb8ff26f9d0e10cfd8a103efd70320a55dc318a84094a7764c560c100cf6e10421ae6d40e6c62891570c604
SHA512
d7781c0b95529bfe89c19615c1dd5952fd4c4b60274e187a641992dad81ef5af921dfb15050ec43169a0c2ad267639642b2e294c5d43405f85a5fb11bb1a939a
diff --git a/net-misc/kea/files/kea-confd-r2 b/net-misc/kea/files/kea-confd-r2
new file mode 100644
index 000000000000..06bc85a5b0ba
--- /dev/null
+++ b/net-misc/kea/files/kea-confd-r2
@@ -0,0 +1,12 @@
+# Which services should be taken into account?
+DHCP4="true"
+DHCP6="false"
+DDNS="false"
+CTRL_AGENT="false"
+
+# Define your config files here. Otherwise we default to files in /etc/kea
+# (see init script)
+#DHCP4_CONFIG="/etc/kea/kea-dhcp4.conf"
+#DHCP6_CONFIG="/etc/kea/kea-dhcp6.conf"
+#DDNS_CONFIG="/etc/kea/kea-dhcp-ddns.conf"
+#CTRL_AGENT_CONFIG="/etc/kea/kea-ctrl-agent.conf"
diff --git a/net-misc/kea/files/kea-ctrl-agent.service-r2
b/net-misc/kea/files/kea-ctrl-agent.service-r2
new file mode 100644
index 000000000000..9901c482ad60
--- /dev/null
+++ b/net-misc/kea/files/kea-ctrl-agent.service-r2
@@ -0,0 +1,16 @@
+[Unit]
+Description=ISC Kea Control Agent
+Before=multi-user.target
+After=remote-fs.target network.target nss-lookup.target time-sync.target
ldap.service ndsd.service
+
+[Service]
+User=dhcp
+Environment=KEA_PIDFILE_DIR=/run/kea
+RuntimeDirectory=kea
+RuntimeDirectoryMode=0750
+ExecStart=/usr/sbin/kea-ctrl-agent -c /etc/kea/kea-ctrl-agent.conf
+ExecReload=kill -HUP $MAINPID
+ProtectSystem=full
+
+[Install]
+WantedBy=multi-user.target
diff --git a/net-misc/kea/files/kea-dhcp-ddns.service-r2
b/net-misc/kea/files/kea-dhcp-ddns.service-r2
new file mode 100644
index 000000000000..7e34895fe884
--- /dev/null
+++ b/net-misc/kea/files/kea-dhcp-ddns.service-r2
@@ -0,0 +1,17 @@
+[Unit]
+Description=ISC Kea DHCP-DDNS server
+Before=multi-user.target
+After=remote-fs.target network.target nss-lookup.target time-sync.target
ldap.service ndsd.service
+
+[Service]
+User=dhcp
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+Environment=KEA_PIDFILE_DIR=/run/kea
+RuntimeDirectory=kea
+RuntimeDirectoryMode=0750
+ExecStart=/usr/sbin/kea-dhcp-ddns -c /etc/kea/kea-dhcp-ddns.conf
+ExecReload=kill -HUP $MAINPID
+ProtectSystem=full
+
+[Install]
+WantedBy=multi-user.target
diff --git a/net-misc/kea/files/kea-dhcp4.service-r2
b/net-misc/kea/files/kea-dhcp4.service-r2
new file mode 100644
index 000000000000..ffac809a0c3e
--- /dev/null
+++ b/net-misc/kea/files/kea-dhcp4.service-r2
@@ -0,0 +1,17 @@
+[Unit]
+Description=ISC Kea DHCPv4 server
+Before=multi-user.target
+After=remote-fs.target network.target nss-lookup.target time-sync.target
ldap.service ndsd.service
+
+[Service]
+User=dhcp
+AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW
+Environment=KEA_PIDFILE_DIR=/run/kea
+RuntimeDirectory=kea
+RuntimeDirectoryMode=0750
+ExecStart=/usr/sbin/kea-dhcp4 -c /etc/kea/kea-dhcp4.conf
+ExecReload=kill -HUP $MAINPID
+ProtectSystem=full
+
+[Install]
+WantedBy=multi-user.target
diff --git a/net-misc/kea/files/kea-dhcp6.service-r2
b/net-misc/kea/files/kea-dhcp6.service-r2
new file mode 100644
index 000000000000..462c530b18a9
--- /dev/null
+++ b/net-misc/kea/files/kea-dhcp6.service-r2
@@ -0,0 +1,17 @@
+[Unit]
+Description=ISC Kea DHCPv6 server
+Before=multi-user.target
+After=remote-fs.target network.target nss-lookup.target time-sync.target
ldap.service ndsd.service
+
+[Service]
+User=dhcp
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+Environment=KEA_PIDFILE_DIR=/run/kea
+RuntimeDirectory=kea
+RuntimeDirectoryMode=0750
+ExecStart=/usr/sbin/kea-dhcp6 -c /etc/kea/kea-dhcp6.conf
+ExecReload=kill -HUP $MAINPID
+ProtectSystem=full
+
+[Install]
+WantedBy=multi-user.target
diff --git a/net-misc/kea/files/kea-initd-r2 b/net-misc/kea/files/kea-initd-r2
new file mode 100644
index 000000000000..31626f25bfed
--- /dev/null
+++ b/net-misc/kea/files/kea-initd-r2
@@ -0,0 +1,147 @@
+#!/sbin/openrc-run
+# Copyright 1999-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+description="kea dhcp services"
+
+dhcp4_command="/usr/sbin/kea-dhcp4"
+dhcp6_command="/usr/sbin/kea-dhcp6"
+ddns_command="/usr/sbin/kea-dhcp-ddns"
+ctrl_agent_command="/usr/sbin/kea-ctrl-agent"
+dhcp4_config="${DHCP4_CONFIG:-/etc/kea/kea-dhcp4.conf}"
+dhcp6_config="${DHCP6_CONFIG:-/etc/kea/kea-dhcp6.conf}"
+ddns_config="${DDNS_CONFIG:-/etc/kea/kea-dhcp-ddns.conf}"
+ctrl_agent_config="${CTRL_AGENT_CONFIG:-/etc/kea/kea-ctrl-agent.conf}"
+dhcp4_pidfile="/run/kea/kea-dhcp4.kea-dhcp4.pid"
+dhcp6_pidfile="/run/kea/kea-dhcp6.kea-dhcp6.pid"
+ddns_pidfile="/run/kea/kea-dhcp-ddns.kea-dhcp-ddns.pid"
+ctrl_agent_pidfile="/run/kea/kea-ctrl-agent.kea-ctrl-agent.pid"
+kea_user="${KEA_USER:-dhcp}"
+kea_group="${KEA_GROUP:-dhcp}"
+
+cap_list="^cap_net_bind_service"
+cap4_list="${cap_list},^cap_net_raw"
+
+depend() {
+ use net
+}
+
+start_pre() {
+ if ${DHCP4:-false} ; then
+ if [ ! -f "${dhcp4_config}" ] ; then
+ eerror "Please create a ${dhcp4_config} config file."
+ return 1
+ fi
+ if [ $(stat -c "%U:%G" ${dhcp4_config}) != "root:${kea_group}"
] ; then
+ eerror "${dhcp4_config} config file is not owned by
root:${kea_group}"
+ eerror "you should reset the ownership:"
+ eerror "chown root:${kea_group} ${dhcp4_config}"
+ return 1
+ fi
+ if ! ${dhcp4_command} -t ${dhcp4_config} 1>/dev/null
2>/dev/null ; then
+ eerror "Error in config file ${dhcp4_config}"
+ return 1
+ fi
+ fi
+ if ${DHCP6:-false} ; then
+ if [ ! -f "${dhcp6_config}" ] ; then
+ eerror "Please create a ${dhcp6_file} config file."
+ return 1
+ fi
+ if [ $(stat -c "%U:%G" ${dhcp6_config}) != "root:${kea_group}"
] ; then
+ eerror "${dhcp6_config} config file is not owned by
root:${kea_group}"
+ eerror "you should reset the ownership:"
+ eerror "chown root:${kea_group} ${dhcp6_config}"
+ return 1
+ fi
+ if ! ${dhcp6_command} -t ${dhcp6_config} 1>/dev/null
2>/dev/null ; then
+ eerror "Error in config file ${dhcp6_config}"
+ return 1
+ fi
+ fi
+ if ${DDNS:-false} ; then
+ if [ ! -f "${ddns_config}" ] ; then
+ eerror "Please create a ${ddns_config} config file."
+ return 1
+ fi
+ if [ $(stat -c "%U:%G" ${ddns_config}) != "root:${kea_group}" ]
; then
+ eerror "${ddns_config} config file is not owned by
root:${kea_group}"
+ eerror "you should reset the ownership:"
+ eerror "chown root:${kea_group} ${ddns_config}"
+ return 1
+ fi
+ if ! ${ddns_command} -t ${ddns_config} 1>/dev/null 2>/dev/null
; then
+ eerror "Error in config file ${ddns_config}"
+ return 1
+ fi
+ fi
+ if ${CTRL_AGENT:-false} ; then
+ if [ ! -f "${ctrl_agent_config}" ] ; then
+ eerror "Please create a ${ctrl_agent_config} config
file."
+ return 1
+ fi
+ if [ $(stat -c "%U:%G" ${ctrl_agent_config}) !=
"root:${kea_group}" ] ; then
+ eerror "${ctrl_agent_config} config file is not owned
by root:${kea_group}"
+ eerror "you should reset the ownership:"
+ eerror "chown root:${kea_group} ${ctrl_agent_config}"
+ return 1
+ fi
+ if ! ${ctrl_agent_command} -t ${ctrl_agent_config} 1>/dev/null
2>/dev/null ; then
+ eerror "Error in config file ${ctrl_agent_config}"
+ return 1
+ fi
+ fi
+}
+
+start() {
+ einfo "Starting kea dhcp services"
+ atleastone=
+ if ${DHCP4:-false} ; then
+ start-stop-daemon -b --capabilities ${cap4_list} -u ${kea_user}
-g ${kea_group} -p ${dhcp4_pidfile} \
+ -x ${dhcp4_command} -- -c ${dhcp4_config} \
+ || return 1
+ atleastone=1
+ fi
+ if ${DHCP6:-false} ; then
+ start-stop-daemon -b --capabilities ${cap_list} -u ${kea_user}
-g ${kea_group} -p ${dhcp6_pidfile} \
+ -x ${dhcp6_command} -- -c ${dhcp6_config} \
+ || return 1
+ atleastone=1
+ fi
+ if ${DDNS:-false} ; then
+ start-stop-daemon -b --capabilities ${cap_list} -u ${kea_user}
-g ${kea_group} -p ${ddns_pidfile} \
+ -x ${ddns_command} -- -c ${ddns_config} \
+ || return 1
+ atleastone=1
+ fi
+ if ${CTRL_AGENT:-false} ; then
+ start-stop-daemon -b -u ${kea_user} -g ${kea_group} -p
${ctrl_agent_pidfile} \
+ -x ${ctrl_agent_command} -- -c ${ctrl_agent_config} \
+ || return 1
+ atleastone=1
+ fi
+ if [ -z ${atleastone} ] ; then
+ eerror "No service has been launched!"
+ return 1
+ fi
+}
+
+stop() {
+ einfo "Stopping kea dhcp services"
+ if ${DHCP4:-false} ; then
+ start-stop-daemon --stop -p ${dhcp4_pidfile} \
+ || return 1
+ fi
+ if ${DHCP6:-false} ; then
+ start-stop-daemon --stop -p ${dhcp6_pidfile} \
+ || return 1
+ fi
+ if ${DDNS:-false} ; then
+ start-stop-daemon --stop -p ${ddns_pidfile} \
+ || return 1
+ fi
+ if ${CTRL_AGENT:-false} ; then
+ start-stop-daemon --stop -p ${ctrl_agent_pidfile} \
+ || return 1
+ fi
+}
diff --git a/net-misc/kea/kea-2.6.3.ebuild b/net-misc/kea/kea-2.6.3.ebuild
new file mode 100644
index 000000000000..b52c810909cc
--- /dev/null
+++ b/net-misc/kea/kea-2.6.3.ebuild
@@ -0,0 +1,253 @@
+# Copyright 1999-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+PYTHON_COMPAT=( python3_{11..14} )
+inherit autotools eapi9-ver flag-o-matic python-r1 systemd tmpfiles
+
+DESCRIPTION="High-performance production grade DHCPv4 & DHCPv6 server"
+HOMEPAGE="https://www.isc.org/kea/"
+
+if [[ ${PV} == *9999* ]]; then
+ inherit git-r3
+ EGIT_REPO_URI="https://gitlab.isc.org/isc-projects/kea.git"
+else
+ SRC_URI="https://downloads.isc.org/isc/kea/${PV}/${P}.tar.gz"
+ KEYWORDS="~amd64 ~arm64 ~x86"
+fi
+
+LICENSE="MPL-2.0"
+SLOT="0"
+IUSE="debug doc mysql +openssl postgres shell test"
+
+REQUIRED_USE="shell? ( ${PYTHON_REQUIRED_USE} )"
+RESTRICT="!test? ( test )"
+
+COMMON_DEPEND="
+ >=dev-libs/boost-1.66:=
+ dev-libs/log4cplus:=
+ mysql? (
+ app-arch/zstd:=
+ dev-db/mysql-connector-c:=
+ dev-libs/openssl:=
+ sys-libs/zlib:=
+ )
+ !openssl? ( dev-libs/botan:2=[boost] )
+ openssl? ( dev-libs/openssl:0= )
+ postgres? ( dev-db/postgresql:* )
+ shell? ( ${PYTHON_DEPS} )
+"
+DEPEND="${COMMON_DEPEND}
+ test? ( dev-cpp/gtest )
+"
+RDEPEND="${COMMON_DEPEND}
+ acct-group/dhcp
+ acct-user/dhcp
+"
+BDEPEND="
+ doc? (
+ $(python_gen_any_dep '
+ dev-python/sphinx[${PYTHON_USEDEP}]
+ dev-python/sphinx-rtd-theme[${PYTHON_USEDEP}]
+ ')
+ )
+ virtual/pkgconfig
+"
+
+PATCHES=(
+ "${FILESDIR}"/${PN}-2.2.0-openssl-version.patch
+)
+
+python_check_deps() {
+ use doc || return 0;
+ python_has_version "dev-python/sphinx[${PYTHON_USEDEP}]" \
+ "dev-python/sphinx-rtd-theme[${PYTHON_USEDEP}]"
+}
+
+pkg_setup() {
+ if use doc || use shell; then
+ python_setup
+ fi
+}
+
+src_prepare() {
+ default
+
+ # set shebang before autotools
+ if use shell; then
+ sed -e 's:^#!@PYTHON@:#!/usr/bin/env python3:' \
+ -i src/bin/shell/kea-shell.in || die
+ fi
+
+ # fix gtest detection
+ sed -e "s:dir/lib/:dir/$(get_libdir)/:" \
+ -i m4macros/ax_gtest.m4 || die
+
+ # skip shell tests that fail to launch daemon in sandbox
+ # may fail to find a suitable interface for generating a DUID-LLT
+ sed -e '/TESTS += $(SHTESTS)$/d' \
+ -i src/bin/dhcp4/tests/Makefile.am \
+ -i src/bin/dhcp6/tests/Makefile.am || die
+ sed -e '/TESTS = $(SHTESTS)$/d' \
+ -i src/bin/keactrl/tests/Makefile.am || die
+
+ # skip shell tests that require a running instance of MySQL
+ if use mysql; then
+ sed -e "/SHTESTS += mysql_tests.sh$/d" \
+ -i src/bin/admin/tests/Makefile.am || die
+ fi
+
+ # skip shell tests that require a running instance of PgSQL
+ if use postgres; then
+ sed -e "/SHTESTS += pgsql_tests.sh$/d" \
+ -i src/bin/admin/tests/Makefile.am || die
+ fi
+
+ # do not create /run
+ sed -e '/$(DESTDIR)${runstatedir}/d' \
+ -i Makefile.am || die
+
+ eautoreconf
+}
+
+src_configure() {
+ # -Werror=odr
+ # https://bugs.gentoo.org/861617
+ #
+ # I would truly love to submit an upstream bug but their self-hosted
gitlab
+ # won't let me sign up. -- Eli
+ filter-lto
+
+ local myeconfargs=(
+ --disable-install-configurations
+ --disable-rpath
+ # manually installed
+ --disable-shell
+ --disable-static
+ --enable-generate-messages
+ --enable-logger-checks
+ --enable-perfdhcp
+ --localstatedir="${EPREFIX}/var"
+ --runstatedir="${EPREFIX}/run"
+ --without-werror
+ --with-log4cplus
+ $(use_enable debug)
+ $(use_enable doc generate-docs)
+ $(use_with mysql)
+ $(use_with openssl)
+ $(use_with postgres pgsql)
+ $(usev test --with-gtest="${EPREFIX}/usr")
+ )
+ econf "${myeconfargs[@]}"
+}
+
+src_test() {
+ local GTEST_SKIP_TESTS=(
+ # may fail when checking addresses on detected interfaces
+ IfaceMgrTest*
+
+ # may fail to find a suitable interface for generating a
DUID-LLT
+ JSONFileBackendTest*
+ CtrlChannelDhcpv6SrvTest*
+
+ # require srv_config_marker_file.txt similarly generated by a
disabled test
+ LoadUnloadDhcpv6SrvTest*
+ )
+
+ # tests that require a running instance of MySQL
+ use mysql && GTEST_SKIP_TESTS+=(
+ *MySql*
+ *MySQL*
+ # conditional tests for MySQL
+ Dhcpv*SrvTest.checkConfigFiles
+ )
+
+ # tests that require a running instance of PgSQL
+ use postgres && GTEST_SKIP_TESTS+=(
+ *PgSql*
+ *PgSQL*
+ # conditional tests for PgSQL
+ Dhcpv*SrvTest.checkConfigFiles
+ )
+
+ local -x GTEST_FILTER
+ [[ -n ${GTEST_SKIP_TESTS[*]} ]] && GTEST_FILTER+="-$( IFS=':'; echo
"${GTEST_SKIP_TESTS[*]}")"
+
+ default
+}
+
+install_shell() {
+ python_domodule src/bin/shell/*.py
+ python_doscript src/bin/shell/kea-shell
+
+ # fix path to import kea modules
+ sed -e "/^sys.path.append/s|(.*)|('$(python_get_sitedir)/${PN}')|"
\
+ -i "${ED}"/usr/lib/python-exec/${EPYTHON}/kea-shell || die
+}
+
+src_install() {
+ emake -j1 install DESTDIR="${D}"
+
+ if use shell; then
+ python_moduleinto ${PN}
+ python_foreach_impl install_shell
+ fi
+
+ dodoc -r doc/examples
+
+ rm -f "${ED}"/usr/share/doc/${P}/COPYING
+
+ diropts -m 0750 -o root -g dhcp
+ dodir /etc/kea
+ insopts -m 0640 -o root -g dhcp
+ insinto /etc/kea
+ newins doc/examples/agent/comments.json kea-ctrl-agent.conf.sample
+ newins doc/examples/kea6/simple.json kea-dhcp6.conf.sample
+ newins doc/examples/kea4/single-subnet.json kea-dhcp4.conf.sample
+ newins doc/examples/ddns/comments.json kea-dhcp-ddns.conf.sample
+
+ # set log to syslog by default
+ sed -e 's/"output": "stdout"/"output": "syslog"/' \
+ -i "${ED}"/etc/kea/*.conf.sample || die
+
+ newconfd "${FILESDIR}"/${PN}-confd-r2 ${PN}
+ newinitd "${FILESDIR}"/${PN}-initd-r2 ${PN}
+
+ systemd_dounit "${FILESDIR}"/${PN}-ctrl-agent.service-r2
+ systemd_dounit "${FILESDIR}"/${PN}-dhcp-ddns.service-r2
+ systemd_dounit "${FILESDIR}"/${PN}-dhcp4.service-r2
+ systemd_dounit "${FILESDIR}"/${PN}-dhcp6.service-r2
+
+ newtmpfiles "${FILESDIR}"/${PN}.tmpfiles.conf ${PN}.conf
+
+ keepdir /var/lib/${PN} /var/log/${PN}
+ fowners -R dhcp:dhcp /var/lib/${PN} /var/log/${PN}
+ fperms 750 /var/lib/${PN} /var/log/${PN}
+
+ find "${ED}" -type f -name "*.la" -delete || die
+}
+
+pkg_postinst() {
+ tmpfiles_process ${PN}.conf
+
+ if ver_replacing -lt 2.6; then
+ ewarn "Several changes have been made for daemons:"
+ ewarn " To comply with common practices for this package,"
+ ewarn " config paths by default has been changed as below:"
+ ewarn " /etc/kea/kea-dhcp4.conf"
+ ewarn " /etc/kea/kea-dhcp6.conf"
+ ewarn " /etc/kea/kea-dhcp-ddns.conf"
+ ewarn " /etc/kea/kea-ctrl-agent.conf"
+ ewarn
+ ewarn " Daemons are launched by default with the unprivileged
user 'dhcp'"
+ ewarn
+ ewarn "Please check your configuration!"
+ fi
+
+ if ! has_version net-misc/kea; then
+ elog "See config files in:"
+ elog " ${EROOT}/etc/kea/*.sample"
+ elog " ${EROOT}/usr/share/doc/${PF}/examples"
+ fi
+}