[nlbuild-autotools] update to 1.6.11 (#3868)

This commit is contained in:
Jonathan Hui
2019-05-24 11:24:30 -07:00
committed by GitHub
14 changed files with 388 additions and 68 deletions
+1 -1
View File
@@ -1 +1 @@
1.6.6
1.6.11
+40
View File
@@ -1,3 +1,43 @@
1.6.11 (2019-05-23)
* Changed the bootstrap shebang from sh to bash to address a
bashism that arrived at 1.6.10.
1.6.10 (2019-05-02)
* Added additional up-front checks to the bootstrap script to
ensure required executables are available.
1.6.9 (2019-04-30)
* Now that both automake and pure make headers and footers are
co-mingled, address an issues in which the .DEFAULT_GOAL
specifications in the repos.mak footer were conflicting with
makefiles that wanted a different default goal by moving
those .DEFAULT_GOAL specifications to Makefile-bootstrap.
1.6.8 (2019-04-29)
* Downgraded m4 from 1.4.17 to 1.4.5 since 1.4.5 seems to be the
last version of m4 that does not abort on invocation in the m4
*rintf and friends compatibility and portability library.
* Leverage both automake and pure make headers and footers by
including the latter in the former.
* Reworked how verbose progress is handled to simplify
specification of progress macros.
* Rebased several automake header macros implementations on their
pure make equivalents.
1.6.7 (2019-04-26)
* Addressed issues with NL_FILTERED_CANONICAL in which the desired
content to be filtered was not filtering correctly and in which
the desired filtered canonical variables were not emitted in
makefiles.
1.6.6 (2019-04-09)
* Added code coverage support for clang, which uses a link flag
@@ -1,4 +1,5 @@
#
# Copyright 2019 Google LLC. All Rights Reserved.
# Copyright 2015-2016 Nest Labs Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,6 +25,59 @@
# care about.
#
#
# _NL_FILTERED_CANONICAL_SPLIT(name)
#
# name - The existing autoconf variable to split
#
# This splits, by CPU architecture, vendor, and OS, the filtered
# tuples otherwise created by autotools, creating:
#
# nl_filtered_<name>
# nl_filtered_<name>_cpu
# nl_filtered_<name>_os
# nl_filtered_<name>_vendor
#
# filtered of the versioning cruft on the vendor component that most
# users of these variables rarely care about.
#
# The resulting values are available both in configure.ac as well
# as in makefiles.
#
_NL_FILTERED_CANONICAL_SPLIT(name)
AC_DEFUN([_NL_FILTERED_CANONICAL_SPLIT],
[
case ${nl_cv_filtered_$1} in
*-*-*) ;;
*) AC_MSG_ERROR([invalid value of canonical $1]);;
esac
AC_SUBST([nl_filtered_$1], [$nl_cv_filtered_$1])
nl_save_IFS=$IFS; IFS='-'
set x $nl_cv_filtered_$1
shift
AC_SUBST([nl_filtered_$1_cpu], [$[1]])
AC_SUBST([nl_filtered_$1_vendor], [$[2]])
shift; shift
[# Remember, the first character of IFS is used to create $]*,
# except with old shells:
nl_filtered_$1_os=$[*]
IFS=$nl_save_IFS
case nl_filtered_$$1_os in
*\ *) nl_filtered_$1_os=`echo "$$1_os" | sed 's/ /-/g'`;;
esac
AC_SUBST([nl_filtered_$1_os])
])
#
# _NL_FILTERED_CANONICAL(name)
#
@@ -40,9 +94,11 @@ _NL_FILTERED_CANONICAL(name)
AC_DEFUN([_NL_FILTERED_CANONICAL],
[
AC_CACHE_CHECK([filtered $1 system type],
nl_cv_filtered_$1,
nl_cv_filtered_$1=`echo ${$1} | sed -e 's/[[[[:digit:].]]]*$//g'`
nl_filtered_$1=${nl_cv_filtered_$1})
[nl_cv_filtered_$1],
[nl_cv_filtered_$1=`echo ${$1} | sed -e 's/[[[:digit:].]]*$//g'`
nl_filtered_$1=${nl_cv_filtered_$1}])
_NL_FILTERED_CANONICAL_SPLIT($1)
])
#
+2
View File
@@ -21,3 +21,5 @@
#
include $(abs_top_nlbuild_autotools_dir)/automake/post/rules.am
include $(abs_top_nlbuild_autotools_dir)/make/post.mak
+2
View File
@@ -21,3 +21,5 @@
#
include $(abs_top_nlbuild_autotools_dir)/automake/pre/macros.am
include $(abs_top_nlbuild_autotools_dir)/make/pre.mak
+4 -12
View File
@@ -1,4 +1,5 @@
#
# Copyright 2019 Google LLC. All Rights Reserved.
# Copyright 2014-2016 Nest Labs Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,7 +34,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre/macros/subdirs.am
# Create the directory with the name of the $(@) variable.
#
define create-directory
$(AM_V_MKDIR_P)$(MKDIR_P) $(@)
$(call nl-create-dir,$(@))
endef # create-directory
#
@@ -43,7 +44,7 @@ endef # create-directory
# the destination of the $(@) variable.
#
define create-link
$(AM_V_LN_S)$(LN_S) $(<) $(@)
$(call nl-create-link)
endef # create-link
#
@@ -68,16 +69,7 @@ endef # create-link
#
#
define check-file
$(AM_V_at)set -e; \
echo ' CHECK $(@)'; \
$(MKDIR_P) $(dir $(@)); \
$(call check-file-$(1),$(<),$(@).N); \
if [ -r "$(@)" ] && $(CMP) -s "$(@)" "$(@).N"; then \
rm -f "$(@).N"; \
else \
echo ' GEN $(@)'; \
mv -f "$(@).N" "$(@)"; \
fi
$(call nl-check-file-with-subroutine,check-file,$(1))
endef # check-file
@@ -1,4 +1,5 @@
#
# Copyright 2019 Google LLC. All Rights Reserved.
# Copyright 2017-2018 Nest Labs Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -57,6 +58,15 @@ abs_top_nlbuild_autotools_dir ?= $(abs_top_srcdir)/$(nlbuild_autotools_stem)
include $(abs_top_nlbuild_autotools_dir)/make/pre.mak
include $(abs_top_nlbuild_autotools_dir)/make/host/tools/bootstrap.mak
# If repos have been defined, create them as the default target goal;
# otherwise, default to help.
ifneq ($(REPOS),)
.DEFAULT_GOAL := repos
else
.DEFAULT_GOAL := help
endif # REPOS
#
# Add any project-specific bootstrap help commands to this
# 'help-hook' target.
+107 -1
View File
@@ -1,5 +1,6 @@
#
# Copyright 2018 Nest Labs Inc. All Rights Reserved.
# Copyright (c) 2019 Google LLC. All Rights Reserved.
# Copyright (c) 2018 Nest Labs Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -25,11 +26,13 @@ CAT ?= cat
CHMOD ?= chmod
CMP ?= cmp
CUT ?= cut
DIFF ?= diff
FIND ?= find
GIT ?= git
GREP ?= grep
GZIP ?= gzip
MKDIR ?= mkdir
MKDIR_P ?= $(MKDIR) -p
MV ?= mv
RMFLAGS = -f
@@ -44,3 +47,106 @@ SORT ?= sort
TAR ?= tar
UNIQ ?= uniq
XZ ?= xz
#
# nl-create-dir <directory>
#
# Create the specified directory, including any parent directories
# that may not exist.
#
define nl-create-dir
$(NL_V_PROGRESS_MKDIR)
$(NL_V_AT)$(MKDIR_P) "$(1)"
endef # nl-create-dir
#
# nl-remove-dir <directory>
#
# If the specified directory exists, then ensure all of the
# directories are writable by the current user, and then forcibly
# remove the directory and all of its contents, sleeping for five (5)
# seconds and failure before trying the removal again.
#
define nl-remove-dir
$(NL_V_PROGRESS_RMDIR)
$(NL_V_AT)if [ -d "$(1)" ]; then \
$(FIND) "$(1)" -type d ! -perm -200 -exec $(CHMOD) u+w {} ';' \
&& $(RM) -rf "$(1)" \
|| { sleep 5 && $(RM) -rf "$(1)"; }; \
fi
endef # nl-remove-dir
#
# nl-check-file-with-subroutine <subroutine prefix> <macro suffix>
#
# Check whether a file, referenced by the $(@) variable, should be
# updated / regenerated based on its dependencies, referenced by the
# $(<) variable by running the make macro check-file-<macro suffix>.
#
# The $(<) is passed as the first argument if the macro wants to process
# it and the prospective new output file, which the macro MUST
# generate, as the second.
#
# This macro will ensure that any required parent directories are created
# prior to invoking the subroutine <subroutine prefix>-<macro suffix>.
#
# This macro is similar to and inspired by that from Linux Kbuild and
# elsewhere.
#
# <subroutine prefix> - The subroutine name, prefixed to "-<macro suffix>",
# which, together with <macro suffix>, indicates the
# make macro to invoke to actually check the file.
#
# <macro suffix> - The name, suffixed to "<subroutine prefix>-", which
# together with <subroutine prefix>, indicates the
# make macro to invoke to actually check the file.
#
#
define nl-check-file-with-subroutine
$(NL_V_AT)set -e; \
$(_NL_PROGRESS) "CHECK" "$(@)"; \
$(MKDIR_P) $(dir $(@)); \
$(call $(1)-$(2),$(<),$(@).N); \
if [ -r "$(@)" ] && $(CMP) -s "$(@)" "$(@).N"; then \
rm -f "$(@).N"; \
else \
$(_NL_PROGRESS) "GEN" "$(@)"; \
mv -f "$(@).N" "$(@)"; \
fi
endef # nl-check-file
#
# nl-check-file <macro suffix>
#
# Check whether a file, referenced by the $(@) variable, should be
# updated / regenerated based on its dependencies, referenced by the
# $(<) variable by running the make macro check-file-<macro suffix>.
#
# The $(<) is passed as the first argument if the macro wants to process
# it and the prospective new output file, which the macro MUST
# generate, as the second.
#
# This macro will ensure that any required parent directories are created
# prior to invoking check-file-<macro suffix>.
#
# This macro is similar to and inspired by that from Linux Kbuild and
# elsewhere.
#
# <macro suffix> - The name, suffixed to "check-file-", which indicates
# the make macro to invoke.
#
#
define nl-check-file
$(call nl-check-file-with-subroutine,nl-check-file,$(1))
endef # nl-check-file
#
# nl-create-link
#
# Create the symbolic link with the source of the $(<) variable and
# the destination of the $(@) variable, using the LN_S macro.
#
define nl-create-link
$(NL_V_PROGRESS_LN_S)
$(NL_V_AT)$(LN_S) $(<) $(@)
endef # nl-create-link
@@ -24,28 +24,35 @@
# the GNU autotools-based build system used by this package.
all check coverage dist distcheck doc docdist install install-headers pretty pretty-check: Makefile
$(NL_V_MAKE)$(MAKE) -f $(<) --no-print-directory $(@)
$(NL_V_PROGRESS_MAKE)
$(MAKE) -f $(<) --no-print-directory $(@)
Makefile: $(top_srcdir)/Makefile.in $(top_srcdir)/configure
$(NL_V_CONFIGURE)$(top_srcdir)/configure
$(NL_V_PROGRESS_CONFIGURE)
$(top_srcdir)/configure
$(top_srcdir)/configure: $(top_srcdir)/configure.ac
$(NL_V_BOOTSTRAP_CONFIG)$(BOOTSTRAP) -w config
$(NL_V_PROGRESS_BOOTSTRAP_CONFIG)
$(BOOTSTRAP) -w config
Makefile.in: Makefile.am
$(NL_V_BOOTSTRAP_MAKE)$(BOOTSTRAP) -w make
$(NL_V_PROGRESS_BOOTSTRAP_MAKE)
$(BOOTSTRAP) -w make
.PHONY: bootstrap
bootstrap:
$(NL_V_BOOTSTRAP_ALL)$(BOOTSTRAP) -w all
$(NL_V_PROGRESS_BOOTSTRAP_ALL)
$(BOOTSTRAP) -w all
.PHONY: bootstrap-config
bootstrap-config:
$(NL_V_BOOTSTRAP_CONFIG)$(BOOTSTRAP) -w config
$(NL_V_PROGRESS_BOOTSTRAP_CONFIG)
$(BOOTSTRAP) -w config
.PHONY: bootstrap-make
bootstrap-make:
$(NL_V_BOOTSTRAP_MAKE)$(BOOTSTRAP) -w make
$(NL_V_PROGRESS_BOOTSTRAP_MAKE)
$(BOOTSTRAP) -w make
define PrintBootstrapHelp
$(NL_V_AT)echo " all"
@@ -120,7 +120,8 @@ $$($(2)_repo_GIT): $(REPOS_PACKAGE_GIT_PATH) | repos-warning
endef # REPOS_template
$(REPOS_PACKAGE_GIT_PATH):
$(NL_V_GIT_INIT)$(GIT) -C $(top_srcdir) init -q $(top_srcdir)
$(NL_V_PROGRESS_GIT_INIT)
$(GIT) -C $(top_srcdir) init -q $(top_srcdir)
$(NL_V_AT)touch $(REPOS_GIT_INIT_SENTINEL)
define PrintReposWarning
@@ -201,13 +202,11 @@ $(NL_V_AT)echo " this package regards as required or optional."
$(NL_V_AT)echo
endef # MaybePrintReposHelp
.DEFAULT_GOAL := repos
else
define MaybePrintReposHelp
endef # MaybePrintReposHelp
.DEFAULT_GOAL := help
endif # REPOS
define PrintReposHelp
@@ -1,4 +1,5 @@
#
# Copyright 2019 Google LLC. All Rights Reserved.
# Copyright 2017-2018 Nest Labs Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,57 +17,85 @@
#
# Description:
# This file is a make "header" or pre make header that defines make macros
# for controlling build verbosity.
# This file is a make "header" or pre make header that defines
# make macros for controlling build verbosity.
#
#
# Verbosity
#
# The default build verbosity is 0 or none. Invoking 'make V=0' is
# equivalent to 'make' with this default.
NL_DEFAULT_VERBOSITY ?= 0
# Alias for the command echo suppression marker.
NL_AT := @
# Alias for a conditional command echo suppression marker, conditioned
# on the build verbosity.
NL_V_AT = $(NL_V_AT_$(V))
NL_V_AT_ = $(NL_V_AT_$(NL_DEFAULT_VERBOSITY))
NL_V_AT_0 = @
NL_V_AT_0 = $(NL_AT)
NL_V_AT_1 =
NL_V_BOOTSTRAP_ALL = $(NL_V_BOOTSTRAP_ALL_$(V))
NL_V_BOOTSTRAP_ALL_ = $(NL_V_BOOTSTRAP_ALL_$(NL_DEFAULT_VERBOSITY))
NL_V_BOOTSTRAP_ALL_0 = @echo " BOOTSTRAP all";
NL_V_BOOTSTRAP_ALL_1 =
#
# Verbosity Build Progress Macros
#
NL_V_BOOTSTRAP_CONFIG = $(NL_V_BOOTSTRAP_CONFIG_$(V))
NL_V_BOOTSTRAP_CONFIG_ = $(NL_V_BOOTSTRAP_CONFIG_$(NL_DEFAULT_VERBOSITY))
NL_V_BOOTSTRAP_CONFIG_0 = @echo " BOOTSTRAP config";
NL_V_BOOTSTRAP_CONFIG_1 =
# Macro for emitting "<ACTION> <target | output>" oneline, succinct
# build progress messages.
NL_V_BOOTSTRAP_MAKE = $(NL_V_BOOTSTRAP_MAKE_$(V))
NL_V_BOOTSTRAP_MAKE_ = $(NL_V_BOOTSTRAP_MAKE_$(NL_DEFAULT_VERBOSITY))
NL_V_BOOTSTRAP_MAKE_0 = @echo " BOOTSTRAP make";
NL_V_BOOTSTRAP_MAKE_1 =
_NL_PROGRESS := printf " %-13s %s\n"
NL_PROGRESS := $(NL_AT)$(_NL_PROGRESS)
NL_V_CONFIGURE = $(NL_V_CONFIGURE_$(V))
NL_V_CONFIGURE_ = $(NL_V_CONFIGURE_$(NL_DEFAULT_VERBOSITY))
NL_V_CONFIGURE_0 = @echo " CONFIGURE";
NL_V_CONFIGURE_1 =
# Macro for emitting "<ACTION> <target | output>" oneline, succinct
# build progress messages, conditioned on build verbosity.
NL_V_GIT_INIT = $(NL_V_GIT_INIT_$(V))
NL_V_GIT_INIT_ = $(NL_V_GIT_INIT_$(NL_DEFAULT_VERBOSITY))
NL_V_GIT_INIT_0 = @echo " GIT INIT $(@)";
NL_V_GIT_INIT_1 =
NL_V_PROGRESS = $(NL_V_PROGRESS_$(V))
NL_V_PROGRESS_ = $(NL_V_PROGRESS_$(NL_DEFAULT_VERBOSITY))
NL_V_PROGRESS_0 = $(NL_PROGRESS)
NL_V_PROGRESS_1 = $(NL_AT)true
NL_V_MAKE = $(NL_V_MAKE_$(V))
NL_V_MAKE_ = $(NL_V_MAKE_$(NL_DEFAULT_VERBOSITY))
NL_V_MAKE_0 = @echo " MAKE $(@)";
NL_V_MAKE_1 =
# Common convenience progress message macros, conditioned on build
# verbosity.
NL_V_MKDIR_P = $(NL_V_MKDIR_P_$(V))
NL_V_MKDIR_P_ = $(NL_V_MKDIR_P_$(NL_DEFAULT_VERBOSITY))
NL_V_MKDIR_P_0 = @echo " MKDIR $(1)";
NL_V_MKDIR_P_1 =
NL_V_PROGRESS_BOOTSTRAP = $(NL_V_PROGRESS) "BOOTSTRAP" "$(1)";
NL_V_PROGRESS_BOOTSTRAP_ALL = $(NL_V_BOOTSTRAP) "all";
NL_V_PROGRESS_BOOTSTRAP_CONFIG = $(NL_V_BOOTSTRAP) "config";
NL_V_PROGRESS_BOOTSTRAP_MAKE = $(NL_V_BOOTSTRAP) "make";
NL_V_RMDIR = $(NL_V_RMDIR_$(V))
NL_V_RMDIR_ = $(NL_V_RMDIR_$(NL_DEFAULT_VERBOSITY))
NL_V_RMDIR_0 = @echo " RMDIR $(1)";
NL_V_RMDIR_1 =
NL_V_PROGRESS_CONFIGURE = $(NL_V_PROGRESS) "CONFIGURE"
NL_V_PROGRESS_GIT_INIT = $(NL_V_PROGRESS) "GIT INIT" "$(@)";
NL_V_PROGRESS_MAKE = $(NL_V_PROGRESS) "MAKE" "$(@)";
NL_V_PROGRESS_LN_S = $(NL_V_PROGRESS) "LN" "$(@)";
NL_V_PROGRESS_MKDIR = $(NL_V_PROGRESS) "MKDIR" "$(1)";
NL_V_PROGRESS_MKDIR_P = $(NL_V_MKDIR)
NL_V_PROGRESS_RMDIR = $(NL_V_PROGRESS) "RMDIR" "$(1)";
NL_V_PROGRESS_GZIP = $(NL_V_PROGRESS) "GZIP" "$(@)";
NL_V_PROGRESS_TAR = $(NL_V_PROGRESS) "TAR" "$(@)";
NL_V_PROGRESS_TGZ = $(NL_V_PROGRESS) "TGZ" "$(@)";
NL_V_PROGRESS_TXZ = $(NL_V_PROGRESS) "TXZ" "$(@)";
NL_V_PROGRESS_XZ = $(NL_V_PROGRESS) "XZ" "$(@)";
#
# Verbosity Commands and Flags
#
# This is useful when we do not want submake to be chatty about what
# it doing when verbosity is suppressed. However, when verbosity is
# requested, -s (silent) would otherwise suppress all make verbose
# output. Consequently, suppress -s when verbosity is requested.
NL_V_MAKE_S = $(NL_V_MAKE_S_$(V))
NL_V_MAKE_S_ = $(NL_V_MAKE_S_$(NL_DEFAULT_VERBOSITY))
NL_V_MAKE_S_0 = $(MAKE) -s
NL_V_MAKE_S_1 = $(MAKE)
+81 -4
View File
@@ -1,6 +1,7 @@
#!/bin/sh
#!/bin/bash
#
# Copyright 2019 Google LLC. All Rights Reserved.
# Copyright 2014-2017 Nest Labs Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,6 +52,75 @@ usage() {
exit $1
}
#
# check_required_executable <path variable> <executable name>
#
# Check to ensure that the named executable with the path in the
# provided variable exists and is executable by the current user.
#
check_required_executable() {
variable="${1}"
path="${!variable}"
name="${2}"
output="${3}"
stem="The required executable '${name}'"
if [ -z "${path}" ]; then
echo "${stem} could not be found."
eval "${output}"="no"
return 1
elif [ ! -e "${path}" ] || [ ! -x "${path}" ]; then
stem="${stem} at '${path}'"
if [ ! -e ${path} ]; then
echo "${stem} does not exist."
elif [ ! -x ${path} ]; then
echo "${stem} is not executable."
fi
echo "Please ensure '${name}' is available in PATH."
eval "${output}"="no"
return 1
fi
eval "${output}"="yes"
return 0
}
check_required_executables()
{
check_required_executable ACLOCAL aclocal have_aclocal
check_required_executable AUTOCONF autoconf have_autoconf
check_required_executable AUTOHEADER autoheader have_autoheader
check_required_executable AUTOMAKE automake have_automake
check_required_executable LIBTOOLIZE libtoolize have_libtoolize
check_required_executable M4 m4 have_m4
if [ "${have_aclocal}" = "no" ] || [ "${have_autoconf}" = "no" ] || [ "${have_autoheader}" = "no" ] || [ "${have_automake}" = "no" ] || [ "${have_libtoolize}" = "no" ] || [ "${have_m4}" = "no" ]; then
cat << EOF
--------------------------------------------------------------------------------
Your build host system is missing one or more of the above executables required
for bootstrapping this nlbuild-autotools-based package. You can either install
these yourself using package management tools available and appropriate for your
build host platform or you can build preselected versions of these executables
from source for this package on this build host by invoking:
make -C ${nlbuild_autotools_dir} tools
and then re-running this script which will use those executables.
--------------------------------------------------------------------------------
EOF
exit 1
fi
}
#
# removetmp
#
@@ -93,13 +163,14 @@ while [ ${#} -gt 0 ]; do
-w|--what)
case "${2}" in
all|make*|conf*|none)
what="${2}"
shift 2
;;
*)
echo "Unknown what value '${2}'."
echo "Unknown what value '${2}'." >&2
usage 1
;;
@@ -117,11 +188,11 @@ done
# is sane.
if [ -z "${nlbuild_autotools_dir}" ]; then
echo "$0: No -I option specified. Please provide the location of the nlbuild-autotools directory."
echo "$0: No -I option specified. Please provide the location of the nlbuild-autotools directory." >&2
exit 1
elif [ ! -d "${nlbuild_autotools_dir}" ]; then
echo "$0: No such directory: ${nlbuild_autotools_dir}. Please provide a valid path to the nlbuild-autotools directory."
echo "$0: No such directory: ${nlbuild_autotools_dir}. Please provide a valid path to the nlbuild-autotools directory." >&2
exit 1
fi
@@ -216,6 +287,12 @@ if [ -r "${abs_top_hostdir}/${host}/bin/libtoolize" ]; then
chmod 775 "${LIBTOOLIZE}"
fi
# Before we get much further, check to ensure that the required
# executables are available and, if not, provide some actionable
# guidance.
check_required_executables
if [ -n "${verbose}" ]; then
echo PATH="${PATH}"
@@ -1 +1 @@
ftp://ftp.gnu.org/pub/gnu/m4/m4-1.4.17.tar.gz
ftp://ftp.gnu.org/pub/gnu/m4/m4-1.4.5.tar.gz
@@ -1 +1 @@
1.4.17
1.4.5