diff options
Diffstat (limited to 'net-wireless/crda')
-rw-r--r-- | net-wireless/crda/Manifest | 1 | ||||
-rw-r--r-- | net-wireless/crda/crda-3.18-r3.ebuild | 83 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-1.1.3-missing-include.patch | 11 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-3.18-cflags.patch | 33 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-3.18-libreg-link.patch | 30 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-3.18-no-ldconfig.patch | 28 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-3.18-no-werror.patch | 32 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-3.18-openssl.patch | 44 | ||||
-rw-r--r-- | net-wireless/crda/files/crda-3.18-python3.patch | 271 |
9 files changed, 533 insertions, 0 deletions
diff --git a/net-wireless/crda/Manifest b/net-wireless/crda/Manifest new file mode 100644 index 000000000..6c7dfaeb2 --- /dev/null +++ b/net-wireless/crda/Manifest @@ -0,0 +1 @@ +DIST crda-3.18.tar.xz 61516 SHA256 43fcb9679f8b75ed87ad10944a506292def13e4afb194afa7aa921b01e8ecdbf SHA512 57ae6309159f396448f052c127f401c2f63d47f4193e87dca231c4b7bbbd7e69b5e5666f356fc76dfc8a6ae58ffa55c3794428d6eb34d9937df77c4276036588 WHIRLPOOL f2ee46b8e25509b6f78e508e62de3f1d0d85303b173b38d653f69f4f6e8f77ada2bc3330cd62646a1ce3819b0db834d9aecc9751cf3e7d35e2a67d3ffdfb1503 diff --git a/net-wireless/crda/crda-3.18-r3.ebuild b/net-wireless/crda/crda-3.18-r3.ebuild new file mode 100644 index 000000000..38f34c57e --- /dev/null +++ b/net-wireless/crda/crda-3.18-r3.ebuild @@ -0,0 +1,83 @@ +# Copyright 1999-2016 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +EAPI=6 + +PYTHON_COMPAT=( python{2_7,3_{3,4,5}} ) +inherit toolchain-funcs python-any-r1 udev + +DESCRIPTION="Central Regulatory Domain Agent for wireless networks" +HOMEPAGE="https://wireless.wiki.kernel.org/en/developers/regulatory/crda" +SRC_URI="http://linuxwireless.org/download/crda/${P}.tar.xz + mirror://kernel/software/network/crda/${P}.tar.xz" + +LICENSE="ISC" +SLOT="0" +KEYWORDS="alpha amd64 arm ~arm64 ~ia64 ~mips ppc ~ppc64 ~sparc x86" +IUSE="gcrypt libressl" + +RDEPEND="!gcrypt? ( + !libressl? ( dev-libs/openssl:0 ) + libressl? ( dev-libs/libressl ) + ) + gcrypt? ( dev-libs/libgcrypt:0 ) + dev-libs/libnl:3 + net-wireless/wireless-regdb" +DEPEND="${RDEPEND} + ${PYTHON_DEPS} + $(python_gen_any_dep 'dev-python/pycrypto[${PYTHON_USEDEP}]') + virtual/pkgconfig" + +PATCHES=( + "${FILESDIR}"/${PN}-3.18-no-ldconfig.patch + "${FILESDIR}"/${PN}-3.18-no-werror.patch + "${FILESDIR}"/${PN}-3.18-openssl.patch + "${FILESDIR}"/${PN}-3.18-cflags.patch + "${FILESDIR}"/${PN}-3.18-libreg-link.patch + "${FILESDIR}"/${PN}-3.18-python3.patch +) + +python_check_deps() { + has_version --host-root "dev-python/pycrypto[${PYTHON_USEDEP}]" +} + +src_prepare() { + default + sed -i \ + -e "s:\<pkg-config\>:$(tc-getPKG_CONFIG):" \ + Makefile || die +} + +_emake() { + # The source hardcodes /usr/lib/crda/ paths (ignoring all make vars + # that look like it should change it). We want to use /usr/lib/ + # anyways as this file is not ABI specific and we want to share it + # among all ABIs rather than pointlessly duplicate it. + # + # The trailing slash on SBINDIR is required by the source. + emake \ + PREFIX="${EPREFIX}/usr" \ + SBINDIR='$(PREFIX)/sbin/' \ + LIBDIR='$(PREFIX)/'"$(get_libdir)" \ + UDEV_RULE_DIR="$(get_udevdir)/rules.d" \ + REG_BIN="${SYSROOT}"/usr/lib/crda/regulatory.bin \ + USE_OPENSSL=$(usex gcrypt 0 1) \ + CC="$(tc-getCC)" \ + V=1 \ + WERROR= \ + "$@" +} + +src_compile() { + _emake all_noverify +} + +src_test() { + _emake verify +} + +src_install() { + _emake DESTDIR="${D}" install + keepdir /etc/wireless-regdb/pubkeys +} diff --git a/net-wireless/crda/files/crda-1.1.3-missing-include.patch b/net-wireless/crda/files/crda-1.1.3-missing-include.patch new file mode 100644 index 000000000..a472e238f --- /dev/null +++ b/net-wireless/crda/files/crda-1.1.3-missing-include.patch @@ -0,0 +1,11 @@ +diff --git a/reglib.c b/reglib.c +index bc81974..1fafd37 100644 +--- a/reglib.c ++++ b/reglib.c +@@ -9,6 +9,7 @@ + #include <fcntl.h> + #include <stdbool.h> + #include <unistd.h> ++#include <string.h> + + #include <arpa/inet.h> /* ntohl */ diff --git a/net-wireless/crda/files/crda-3.18-cflags.patch b/net-wireless/crda/files/crda-3.18-cflags.patch new file mode 100644 index 000000000..6edbded82 --- /dev/null +++ b/net-wireless/crda/files/crda-3.18-cflags.patch @@ -0,0 +1,33 @@ +From c5b0741ea7fc12e9f6a2a309296ed412a999d0f7 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger <vapier@chromium.org> +Date: Wed, 4 Mar 2015 14:09:50 -0500 +Subject: [PATCH] clean up CFLAGS handling + +Rather than append -O2 -g all the time to the user's CFLAGS (and thus +clobbering whatever they have set up), initialize the default value to +that and let the user override it entirely. + +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +--- + Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Makefile b/Makefile +index 5f988f4..8e345a1 100644 +--- a/Makefile ++++ b/Makefile +@@ -26,9 +26,9 @@ PUBKEY_DIR?=pubkeys + RUNTIME_PUBKEY_DIR?=/etc/wireless-regdb/pubkeys + + WERROR = -Werror +-CFLAGS += -O2 -fpic ++CFLAGS ?= -O2 -g ++CFLAGS += -fpic + CFLAGS += -std=gnu99 -Wall $(WERROR) -pedantic +-CFLAGS += -Wall -g + LDLIBREG += -lreg + LDLIBS += $(LDLIBREG) + LDLIBS += -lm +-- +2.3.1 + diff --git a/net-wireless/crda/files/crda-3.18-libreg-link.patch b/net-wireless/crda/files/crda-3.18-libreg-link.patch new file mode 100644 index 000000000..0aa1b6e87 --- /dev/null +++ b/net-wireless/crda/files/crda-3.18-libreg-link.patch @@ -0,0 +1,30 @@ +https://bugs.gentoo.org/542436 + +From f56ab87b25f2228a67ac592a1c18793c72dd03eb Mon Sep 17 00:00:00 2001 +From: Mike Frysinger <vapier@gentoo.org> +Date: Sat, 7 Mar 2015 22:29:33 -0500 +Subject: [PATCH crda] libreg: link against crypto libs + +Since libreg uses funcs from the crypto lib, make sure we link them. + +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 8e345a1..77708e6 100644 +--- a/Makefile ++++ b/Makefile +@@ -117,7 +117,7 @@ keys-%.c: utils/key2pub.py $(wildcard $(PUBKEY_DIR)/*.pem) + + $(LIBREG): regdb.h reglib.h reglib.c + $(NQ) ' CC ' $@ +- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -shared -Wl,-soname,$(LIBREG) $^ ++ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -shared -Wl,-soname,$(LIBREG) $^ $(filter-out -lreg,$(LDLIBS)) + + install-libreg-headers: + $(NQ) ' INSTALL libreg-headers' +-- +2.3.1 + diff --git a/net-wireless/crda/files/crda-3.18-no-ldconfig.patch b/net-wireless/crda/files/crda-3.18-no-ldconfig.patch new file mode 100644 index 000000000..a5cc42084 --- /dev/null +++ b/net-wireless/crda/files/crda-3.18-no-ldconfig.patch @@ -0,0 +1,28 @@ +From b11d83df189670defe4a29c624f2930351c13df2 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger <vapier@gentoo.org> +Date: Wed, 4 Mar 2015 13:56:36 -0500 +Subject: [PATCH] do not run ldconfig + +Let the distro/user deal with ldconfig updating. Running it blindly like +this breaks DESTDIR installs as `ldconfig` only operates on system paths. + +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +--- + Makefile | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/Makefile b/Makefile +index a3ead30..46c683d 100644 +--- a/Makefile ++++ b/Makefile +@@ -127,7 +127,6 @@ install-libreg: + $(NQ) ' INSTALL libreg' + $(Q)mkdir -p $(DESTDIR)/$(LIBDIR) + $(Q)cp $(LIBREG) $(DESTDIR)/$(LIBDIR)/ +- $(Q)ldconfig + + %.o: %.c regdb.h $(LIBREG) + $(NQ) ' CC ' $@ +-- +2.3.1 + diff --git a/net-wireless/crda/files/crda-3.18-no-werror.patch b/net-wireless/crda/files/crda-3.18-no-werror.patch new file mode 100644 index 000000000..6abb78c98 --- /dev/null +++ b/net-wireless/crda/files/crda-3.18-no-werror.patch @@ -0,0 +1,32 @@ +From 37384d22ba0ab622a5848a9a794084e6064fc905 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger <vapier@chromium.org> +Date: Wed, 4 Mar 2015 14:03:44 -0500 +Subject: [PATCH] allow people to turn off -Werror + +Forcing -Werror at build time easily breaks across compiler settings, +compiler versions, architectures, C libraries, etc... Add a knob so +distro peeps can turn it off. + +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +--- + Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 46c683d..5f988f4 100644 +--- a/Makefile ++++ b/Makefile +@@ -25,8 +25,9 @@ UDEV_RULE_DIR?=/lib/udev/rules.d/ + PUBKEY_DIR?=pubkeys + RUNTIME_PUBKEY_DIR?=/etc/wireless-regdb/pubkeys + ++WERROR = -Werror + CFLAGS += -O2 -fpic +-CFLAGS += -std=gnu99 -Wall -Werror -pedantic ++CFLAGS += -std=gnu99 -Wall $(WERROR) -pedantic + CFLAGS += -Wall -g + LDLIBREG += -lreg + LDLIBS += $(LDLIBREG) +-- +2.3.1 + diff --git a/net-wireless/crda/files/crda-3.18-openssl.patch b/net-wireless/crda/files/crda-3.18-openssl.patch new file mode 100644 index 000000000..9147e862e --- /dev/null +++ b/net-wireless/crda/files/crda-3.18-openssl.patch @@ -0,0 +1,44 @@ +From af009b7599d705a1023d7bc95c485e5a8776d2b8 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger <vapier@chromium.org> +Date: Wed, 4 Mar 2015 14:07:37 -0500 +Subject: [PATCH] fix openssl generation + +This file uses BN_ULONG but doesn't include the openssl headers leading +to build failures: +keys-ssl.c:2:8: error: unknown type name 'BN_ULONG' + static BN_ULONG e_0[1] = { + +The large unqualified constants also break building: +keys-ssl.c:8:2: warning: overflow in implicit constant conversion [-Woverflow] + 0x63a2705416a0d8e1, 0xdc9fca11c8ba757b, + ^ + +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +--- + utils/key2pub.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/utils/key2pub.py b/utils/key2pub.py +index 3e84cd2..c504aca 100755 +--- a/utils/key2pub.py ++++ b/utils/key2pub.py +@@ -24,7 +24,7 @@ def print_ssl_64(output, name, val): + for v1, v2, v3, v4, v5, v6, v7, v8 in vnew: + if not idx: + output.write('\t') +- output.write('0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x, ' % (ord(v1), ord(v2), ord(v3), ord(v4), ord(v5), ord(v6), ord(v7), ord(v8))) ++ output.write('0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2xULL, ' % (ord(v1), ord(v2), ord(v3), ord(v4), ord(v5), ord(v6), ord(v7), ord(v8))) + idx += 1 + if idx == 2: + idx = 0 +@@ -60,6 +60,7 @@ def print_ssl_32(output, name, val): + def print_ssl(output, name, val): + import struct + output.write('#include <stdint.h>\n') ++ output.write('#include <openssl/bn.h>\n') + if len(struct.pack('@L', 0)) == 8: + return print_ssl_64(output, name, val) + else: +-- +2.3.1 + diff --git a/net-wireless/crda/files/crda-3.18-python3.patch b/net-wireless/crda/files/crda-3.18-python3.patch new file mode 100644 index 000000000..4f8756862 --- /dev/null +++ b/net-wireless/crda/files/crda-3.18-python3.patch @@ -0,0 +1,271 @@ +From 797f2836c48f9ba2446629ae4b6867ca1a5ea512 Mon Sep 17 00:00:00 2001 +From: Taahir Ahmed <ahmed.taahir@gmail.com> +Date: Wed, 30 Mar 2016 11:23:54 -0300 +Subject: [PATCH 1/2] crda: support python 3 in utils/key2pub.py + +utils/key2pub.py can now be run under either python 2.7 or python 3.x. +This required some minor syntactical changes as well as switching from +M2Crypto to pycrypto, since M2Crypto doesn't support python 3.x. + +In addition, some errors in the generated source file keys-ssl.h are +fixed: + + * The correct OpenSSL header for BN_ULONG is included. + + * The generated constants are given the 'ull' suffix to prevent + warnings about constants that are too large. + +[Gustavo: don't call /utils/key2pub.py since that doesn't compute] + +Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar> +--- +Status: submitted upstream by author but not (yet) accepted +URL: http://www.spinics.net/lists/linux-wireless/msg138936.html + + Makefile | 2 +- + utils/key2pub.py | 146 ++++++++++++++++++++++++++++--------------------------- + 2 files changed, 75 insertions(+), 73 deletions(-) + +diff --git a/Makefile b/Makefile +index 1f25509..523a96e 100644 +--- a/Makefile ++++ b/Makefile +@@ -112,7 +112,7 @@ $(REG_BIN): + keys-%.c: utils/key2pub.py $(wildcard $(PUBKEY_DIR)/*.pem) + $(NQ) ' GEN ' $@ + $(NQ) ' Trusted pubkeys:' $(wildcard $(PUBKEY_DIR)/*.pem) +- $(Q)./utils/key2pub.py --$* $(wildcard $(PUBKEY_DIR)/*.pem) $@ ++ $(Q) python utils/key2pub.py --$* $(wildcard $(PUBKEY_DIR)/*.pem) $@ + + $(LIBREG): regdb.h reglib.h reglib.c + $(NQ) ' CC ' $@ +diff --git a/utils/key2pub.py b/utils/key2pub.py +index 3e84cd2..c76cbbb 100755 +--- a/utils/key2pub.py ++++ b/utils/key2pub.py +@@ -1,126 +1,128 @@ + #!/usr/bin/env python + ++import io + import sys + try: +- from M2Crypto import RSA +-except ImportError, e: +- sys.stderr.write('ERROR: Failed to import the "M2Crypto" module: %s\n' % e.message) +- sys.stderr.write('Please install the "M2Crypto" Python module.\n') +- sys.stderr.write('On Debian GNU/Linux the package is called "python-m2crypto".\n') +- sys.exit(1) ++ from Crypto.PublicKey import RSA ++except ImportError as e: ++ sys.stderr.write('ERROR: Failed to import the "Crypto.PublicKey" module: %s\n' % e.message) ++ sys.stderr.write('Please install the "Crypto.PublicKey" Python module.\n') ++ sys.stderr.write('On Debian GNU/Linux the package is called "python-crypto".\n') ++ sys.exit(1) ++ ++def bitwise_collect(value, radix_bits): ++ words = [] ++ radix_mask = (1 << radix_bits) - 1 ++ while value != 0: ++ words.append(value & radix_mask) ++ value >>= radix_bits ++ return words + + def print_ssl_64(output, name, val): +- while val[0] == '\0': +- val = val[1:] +- while len(val) % 8: +- val = '\0' + val +- vnew = [] +- while len(val): +- vnew.append((val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7])) +- val = val[8:] +- vnew.reverse() +- output.write('static BN_ULONG %s[%d] = {\n' % (name, len(vnew))) ++ # OpenSSL expects 64-bit words given least-significant-word first. ++ vwords = bitwise_collect(val, 64) ++ ++ output.write(u'static BN_ULONG {}[] = {{\n'.format(name)) + idx = 0 +- for v1, v2, v3, v4, v5, v6, v7, v8 in vnew: ++ for vword in vwords: + if not idx: +- output.write('\t') +- output.write('0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2xULL, ' % (ord(v1), ord(v2), ord(v3), ord(v4), ord(v5), ord(v6), ord(v7), ord(v8))) ++ output.write(u'\t') ++ output.write(u'0x{:016x}ULL, '.format(vword)) + idx += 1 + if idx == 2: + idx = 0 +- output.write('\n') ++ output.write(u'\n') + if idx: +- output.write('\n') +- output.write('};\n\n') ++ output.write(u'\n') ++ output.write(u'};\n\n') + + def print_ssl_32(output, name, val): +- while val[0] == '\0': +- val = val[1:] +- while len(val) % 4: +- val = '\0' + val +- vnew = [] +- while len(val): +- vnew.append((val[0], val[1], val[2], val[3], )) +- val = val[4:] +- vnew.reverse() +- output.write('static BN_ULONG %s[%d] = {\n' % (name, len(vnew))) ++ # OpenSSL expects 32-bit words given least-significant-word first. ++ vwords = bitwise_collect(val, 32) ++ ++ output.write(u'static BN_ULONG {}[] = {{\n'.format(name)) + idx = 0 +- for v1, v2, v3, v4 in vnew: ++ for vword in vwords: + if not idx: +- output.write('\t') +- output.write('0x%.2x%.2x%.2x%.2x, ' % (ord(v1), ord(v2), ord(v3), ord(v4))) ++ output.write(u'\t') ++ output.write(u'0x{:08x}, '.format(vword)) + idx += 1 + if idx == 4: + idx = 0 +- output.write('\n') ++ output.write(u'\n') + if idx: +- output.write('\n') +- output.write('};\n\n') ++ output.write(u'\n') ++ output.write(u'};\n\n') + + def print_ssl(output, name, val): ++ ++ output.write(u'#include <stdint.h>\n') ++ output.write(u'#include <openssl/bn.h>\n') ++ + import struct +- output.write('#include <stdint.h>\n') + if len(struct.pack('@L', 0)) == 8: + return print_ssl_64(output, name, val) + else: + return print_ssl_32(output, name, val) + + def print_ssl_keys(output, n): +- output.write(r''' ++ output.write(u''' + struct pubkey { + struct bignum_st e, n; + }; + +-#define KEY(data) { \ +- .d = data, \ +- .top = sizeof(data)/sizeof(data[0]), \ ++#define KEY(data) { \\ ++ .d = data, \\ ++ .top = sizeof(data)/sizeof(data[0]), \\ + } + +-#define KEYS(e,n) { KEY(e), KEY(n), } ++#define KEYS(e,n) { KEY(e), KEY(n), } + + static struct pubkey keys[] = { + ''') + for n in xrange(n + 1): +- output.write(' KEYS(e_%d, n_%d),\n' % (n, n)) +- output.write('};\n') ++ output.write(u' KEYS(e_{0}, n_{0}),\n'.format(n)) ++ output.write(u'};\n') + pass + + def print_gcrypt(output, name, val): +- output.write('#include <stdint.h>\n') +- while val[0] == '\0': +- val = val[1:] +- output.write('static const uint8_t %s[%d] = {\n' % (name, len(val))) ++ # gcrypt expects 8-bit words most-significant-word first ++ vwords = bitwise_collect(val, 8) ++ vwords.reverse() ++ ++ output.write(u'#include <stdint.h>\n') ++ output.write(u'static const uint8_t %s[%d] = {\n' % (name, len(vwords))) + idx = 0 +- for v in val: ++ for vword in vwords: + if not idx: +- output.write('\t') +- output.write('0x%.2x, ' % ord(v)) ++ output.write(u'\t') ++ output.write(u'0x{:02x}, '.format(vword)) + idx += 1 + if idx == 8: + idx = 0 +- output.write('\n') ++ output.write(u'\n') + if idx: +- output.write('\n') +- output.write('};\n\n') ++ output.write(u'\n') ++ output.write(u'};\n\n') + + def print_gcrypt_keys(output, n): +- output.write(r''' ++ output.write(u''' + struct key_params { + const uint8_t *e, *n; + uint32_t len_e, len_n; + }; + +-#define KEYS(_e, _n) { \ +- .e = _e, .len_e = sizeof(_e), \ +- .n = _n, .len_n = sizeof(_n), \ ++#define KEYS(_e, _n) { \\ ++ .e = _e, .len_e = sizeof(_e), \\ ++ .n = _n, .len_n = sizeof(_n), \\ + } + + static const struct key_params keys[] = { + ''') +- for n in xrange(n + 1): +- output.write(' KEYS(e_%d, n_%d),\n' % (n, n)) +- output.write('};\n') +- ++ for n in range(n + 1): ++ output.write(u' KEYS(e_{0}, n_{0}),\n'.format(n)) ++ output.write(u'};\n') ++ + + modes = { + '--ssl': (print_ssl, print_ssl_keys), +@@ -135,21 +137,21 @@ except IndexError: + mode = None + + if not mode in modes: +- print 'Usage: %s [%s] input-file... output-file' % (sys.argv[0], '|'.join(modes.keys())) ++ print('Usage: {} [{}] input-file... output-file'.format(sys.argv[0], '|'.join(modes.keys()))) + sys.exit(2) + +-output = open(outfile, 'w') ++output = io.open(outfile, 'w') + + # load key + idx = 0 + for f in files: +- try: +- key = RSA.load_pub_key(f) +- except RSA.RSAError: +- key = RSA.load_key(f) + +- modes[mode][0](output, 'e_%d' % idx, key.e[4:]) +- modes[mode][0](output, 'n_%d' % idx, key.n[4:]) ++ key_contents = io.open(f, 'rb').read() ++ key = RSA.importKey(key_contents) ++ ++ modes[mode][0](output, 'e_{}'.format(idx), key.e) ++ modes[mode][0](output, 'n_{}'.format(idx), key.n) ++ + idx += 1 + + modes[mode][1](output, idx - 1) +-- +2.7.3 + |